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

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

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
« no previous file with comments | « runtime/vm/flow_graph_range_analysis.h ('k') | runtime/vm/flow_graph_range_analysis_test.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 #include "vm/flow_graph_range_analysis.h" 5 #include "vm/flow_graph_range_analysis.h"
6 6
7 #include "vm/bit_vector.h" 7 #include "vm/bit_vector.h"
8 #include "vm/il_printer.h" 8 #include "vm/il_printer.h"
9 9
10 namespace dart { 10 namespace dart {
11 11
12 DEFINE_FLAG(bool, array_bounds_check_elimination, true, 12 DEFINE_FLAG(bool, array_bounds_check_elimination, true,
13 "Eliminate redundant bounds checks."); 13 "Eliminate redundant bounds checks.");
14 DEFINE_FLAG(bool, trace_range_analysis, false, "Trace range analysis progress"); 14 DEFINE_FLAG(bool, trace_range_analysis, false, "Trace range analysis progress");
15 DEFINE_FLAG(bool, trace_integer_ir_selection, false, 15 DEFINE_FLAG(bool, trace_integer_ir_selection, false,
16 "Print integer IR selection optimization pass."); 16 "Print integer IR selection optimization pass.");
17 DECLARE_FLAG(bool, trace_constant_propagation); 17 DECLARE_FLAG(bool, trace_constant_propagation);
18 18
19 // Quick access to the locally defined isolate() method. 19 // Quick access to the locally defined isolate() method.
20 #define I (isolate()) 20 #define I (isolate())
21 21
22 void RangeAnalysis::Analyze() { 22 void RangeAnalysis::Analyze() {
23 CollectValues(); 23 CollectValues();
24
25 if (FLAG_trace_range_analysis) {
26 FlowGraphPrinter::PrintGraph("Range Analysis (BBB)", flow_graph_);
27 }
28
24 InsertConstraints(); 29 InsertConstraints();
25 InferRanges(); 30 InferRanges();
31 EliminateRedundantBoundsChecks();
32 MarkUnreachableBlocks();
33
26 IntegerInstructionSelector iis(flow_graph_); 34 IntegerInstructionSelector iis(flow_graph_);
27 iis.Select(); 35 iis.Select();
36
28 RemoveConstraints(); 37 RemoveConstraints();
29 } 38 }
30 39
31 40
32 void RangeAnalysis::CollectValues() { 41 void RangeAnalysis::CollectValues() {
33 const GrowableArray<Definition*>& initial = 42 const GrowableArray<Definition*>& initial =
34 *flow_graph_->graph_entry()->initial_definitions(); 43 *flow_graph_->graph_entry()->initial_definitions();
35 for (intptr_t i = 0; i < initial.length(); ++i) { 44 for (intptr_t i = 0; i < initial.length(); ++i) {
36 Definition* current = initial[i]; 45 Definition* current = initial[i];
37 if (current->Type()->ToCid() == kSmiCid) { 46 if (current->Type()->ToCid() == kSmiCid) {
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
77 Instruction* current = instr_it.Current(); 86 Instruction* current = instr_it.Current();
78 Definition* defn = current->AsDefinition(); 87 Definition* defn = current->AsDefinition();
79 if (defn != NULL) { 88 if (defn != NULL) {
80 if ((defn->Type()->ToCid() == kSmiCid) && 89 if ((defn->Type()->ToCid() == kSmiCid) &&
81 (defn->ssa_temp_index() != -1)) { 90 (defn->ssa_temp_index() != -1)) {
82 values_.Add(defn); 91 values_.Add(defn);
83 } else if ((defn->IsMintDefinition()) && 92 } else if ((defn->IsMintDefinition()) &&
84 (defn->ssa_temp_index() != -1)) { 93 (defn->ssa_temp_index() != -1)) {
85 values_.Add(defn); 94 values_.Add(defn);
86 } 95 }
87 } else if (current->IsCheckSmi()) { 96 } else if (current->IsCheckArrayBound()) {
88 smi_checks_.Add(current->AsCheckSmi()); 97 bounds_checks_.Add(current->AsCheckArrayBound());
89 } 98 }
90 } 99 }
91 } 100 }
92 } 101 }
93 102
94 103
95 // Returns true if use is dominated by the given instruction. 104 // Returns true if use is dominated by the given instruction.
96 // Note: uses that occur at instruction itself are not dominated by it. 105 // Note: uses that occur at instruction itself are not dominated by it.
97 static bool IsDominatedUse(Instruction* dom, Value* use) { 106 static bool IsDominatedUse(Instruction* dom, Value* use) {
98 BlockEntryInstr* dom_block = dom->GetBlock(); 107 BlockEntryInstr* dom_block = dom->GetBlock();
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
153 return Token::kILLEGAL; 162 return Token::kILLEGAL;
154 } 163 }
155 } 164 }
156 165
157 166
158 // Given a boundary (right operand) and a comparison operation return 167 // Given a boundary (right operand) and a comparison operation return
159 // a symbolic range constraint for the left operand of the comparison assuming 168 // a symbolic range constraint for the left operand of the comparison assuming
160 // that it evaluated to true. 169 // that it evaluated to true.
161 // For example for the comparison a < b symbol a is constrained with range 170 // For example for the comparison a < b symbol a is constrained with range
162 // [Smi::kMinValue, b - 1]. 171 // [Smi::kMinValue, b - 1].
163 Range* RangeAnalysis::ConstraintRange(Token::Kind op, Definition* boundary) { 172 Range* RangeAnalysis::ConstraintSmiRange(Token::Kind op, Definition* boundary) {
164 switch (op) { 173 switch (op) {
165 case Token::kEQ: 174 case Token::kEQ:
166 return new(I) Range(RangeBoundary::FromDefinition(boundary), 175 return new(I) Range(RangeBoundary::FromDefinition(boundary),
167 RangeBoundary::FromDefinition(boundary)); 176 RangeBoundary::FromDefinition(boundary));
168 case Token::kNE: 177 case Token::kNE:
169 return Range::Unknown(); 178 return new(I) Range(Range::Full(RangeBoundary::kRangeBoundarySmi));
170 case Token::kLT: 179 case Token::kLT:
171 return new(I) Range(RangeBoundary::MinSmi(), 180 return new(I) Range(RangeBoundary::MinSmi(),
172 RangeBoundary::FromDefinition(boundary, -1)); 181 RangeBoundary::FromDefinition(boundary, -1));
173 case Token::kGT: 182 case Token::kGT:
174 return new(I) Range(RangeBoundary::FromDefinition(boundary, 1), 183 return new(I) Range(RangeBoundary::FromDefinition(boundary, 1),
175 RangeBoundary::MaxSmi()); 184 RangeBoundary::MaxSmi());
176 case Token::kLTE: 185 case Token::kLTE:
177 return new(I) Range(RangeBoundary::MinSmi(), 186 return new(I) Range(RangeBoundary::MinSmi(),
178 RangeBoundary::FromDefinition(boundary)); 187 RangeBoundary::FromDefinition(boundary));
179 case Token::kGTE: 188 case Token::kGTE:
180 return new(I) Range(RangeBoundary::FromDefinition(boundary), 189 return new(I) Range(RangeBoundary::FromDefinition(boundary),
181 RangeBoundary::MaxSmi()); 190 RangeBoundary::MaxSmi());
182 default: 191 default:
183 UNREACHABLE(); 192 UNREACHABLE();
184 return Range::Unknown(); 193 return NULL;
185 } 194 }
186 } 195 }
187 196
188 197
189 ConstraintInstr* RangeAnalysis::InsertConstraintFor(Definition* defn, 198 ConstraintInstr* RangeAnalysis::InsertConstraintFor(Value* use,
199 Definition* defn,
190 Range* constraint_range, 200 Range* constraint_range,
191 Instruction* after) { 201 Instruction* after) {
202 // Avoid constraining inside the dead code.
203 if (!use->IsSmiValue()) return NULL;
204
192 // No need to constrain constants. 205 // No need to constrain constants.
193 if (defn->IsConstant()) return NULL; 206 if (defn->IsConstant()) return NULL;
194 207
195 ConstraintInstr* constraint = new(I) ConstraintInstr( 208 // Check if the value is already constrained to avoid inserting duplicated
196 new(I) Value(defn), constraint_range); 209 // constraints.
210 ConstraintInstr* constraint = after->next()->AsConstraint();
211 while (constraint != NULL) {
212 if ((constraint->value()->definition() == defn) &&
213 constraint->constraint()->Equals(constraint_range)) {
214 return NULL;
215 }
216 constraint = constraint->next()->AsConstraint();
217 }
218
219 constraint = new(I) ConstraintInstr(
220 use->CopyWithType(), constraint_range);
221
197 flow_graph_->InsertAfter(after, constraint, NULL, FlowGraph::kValue); 222 flow_graph_->InsertAfter(after, constraint, NULL, FlowGraph::kValue);
198 RenameDominatedUses(defn, constraint, constraint); 223 RenameDominatedUses(defn, constraint, constraint);
199 constraints_.Add(constraint); 224 constraints_.Add(constraint);
200 return constraint; 225 return constraint;
201 } 226 }
202 227
203 228
204 void RangeAnalysis::ConstrainValueAfterBranch(Definition* defn, Value* use) { 229 void RangeAnalysis::ConstrainValueAfterBranch(Value* use, Definition* defn) {
205 BranchInstr* branch = use->instruction()->AsBranch(); 230 BranchInstr* branch = use->instruction()->AsBranch();
206 RelationalOpInstr* rel_op = branch->comparison()->AsRelationalOp(); 231 RelationalOpInstr* rel_op = branch->comparison()->AsRelationalOp();
207 if ((rel_op != NULL) && (rel_op->operation_cid() == kSmiCid)) { 232 if ((rel_op != NULL) && (rel_op->operation_cid() == kSmiCid)) {
208 // Found comparison of two smis. Constrain defn at true and false 233 // Found comparison of two smis. Constrain defn at true and false
209 // successors using the other operand as a boundary. 234 // successors using the other operand as a boundary.
210 Definition* boundary; 235 Definition* boundary;
211 Token::Kind op_kind; 236 Token::Kind op_kind;
212 if (use->use_index() == 0) { // Left operand. 237 if (use->use_index() == 0) { // Left operand.
213 boundary = rel_op->InputAt(1)->definition(); 238 boundary = rel_op->InputAt(1)->definition();
214 op_kind = rel_op->kind(); 239 op_kind = rel_op->kind();
215 } else { 240 } else {
216 ASSERT(use->use_index() == 1); // Right operand. 241 ASSERT(use->use_index() == 1); // Right operand.
217 boundary = rel_op->InputAt(0)->definition(); 242 boundary = rel_op->InputAt(0)->definition();
218 // InsertConstraintFor assumes that defn is left operand of a 243 // InsertConstraintFor assumes that defn is left operand of a
219 // comparison if it is right operand flip the comparison. 244 // comparison if it is right operand flip the comparison.
220 op_kind = FlipComparison(rel_op->kind()); 245 op_kind = FlipComparison(rel_op->kind());
221 } 246 }
222 247
223 // Constrain definition at the true successor. 248 // Constrain definition at the true successor.
224 ConstraintInstr* true_constraint = 249 ConstraintInstr* true_constraint =
225 InsertConstraintFor(defn, 250 InsertConstraintFor(use,
226 ConstraintRange(op_kind, boundary), 251 defn,
252 ConstraintSmiRange(op_kind, boundary),
227 branch->true_successor()); 253 branch->true_successor());
228 // Mark true_constraint an artificial use of boundary. This ensures 254 // Mark true_constraint an artificial use of boundary. This ensures
229 // that constraint's range is recalculated if boundary's range changes. 255 // that constraint's range is recalculated if boundary's range changes.
230 if (true_constraint != NULL) { 256 if (true_constraint != NULL) {
231 true_constraint->AddDependency(boundary); 257 true_constraint->AddDependency(boundary);
232 true_constraint->set_target(branch->true_successor()); 258 true_constraint->set_target(branch->true_successor());
233 } 259 }
234 260
235 // Constrain definition with a negated condition at the false successor. 261 // Constrain definition with a negated condition at the false successor.
236 ConstraintInstr* false_constraint = 262 ConstraintInstr* false_constraint =
237 InsertConstraintFor( 263 InsertConstraintFor(
264 use,
238 defn, 265 defn,
239 ConstraintRange(Token::NegateComparison(op_kind), boundary), 266 ConstraintSmiRange(Token::NegateComparison(op_kind), boundary),
240 branch->false_successor()); 267 branch->false_successor());
241 // Mark false_constraint an artificial use of boundary. This ensures 268 // Mark false_constraint an artificial use of boundary. This ensures
242 // that constraint's range is recalculated if boundary's range changes. 269 // that constraint's range is recalculated if boundary's range changes.
243 if (false_constraint != NULL) { 270 if (false_constraint != NULL) {
244 false_constraint->AddDependency(boundary); 271 false_constraint->AddDependency(boundary);
245 false_constraint->set_target(branch->false_successor()); 272 false_constraint->set_target(branch->false_successor());
246 } 273 }
247 } 274 }
248 } 275 }
249 276
250 277
251 void RangeAnalysis::InsertConstraintsFor(Definition* defn) { 278 void RangeAnalysis::InsertConstraintsFor(Definition* defn) {
252 for (Value* use = defn->input_use_list(); 279 for (Value* use = defn->input_use_list();
253 use != NULL; 280 use != NULL;
254 use = use->next_use()) { 281 use = use->next_use()) {
255 if (use->instruction()->IsBranch()) { 282 if (use->instruction()->IsBranch()) {
256 ConstrainValueAfterBranch(defn, use); 283 ConstrainValueAfterBranch(use, defn);
257 } else if (use->instruction()->IsCheckArrayBound()) { 284 } else if (use->instruction()->IsCheckArrayBound()) {
258 ConstrainValueAfterCheckArrayBound( 285 ConstrainValueAfterCheckArrayBound(use, defn);
259 defn,
260 use->instruction()->AsCheckArrayBound(),
261 use->use_index());
262 } 286 }
263 } 287 }
264 } 288 }
265 289
266 290
267 void RangeAnalysis::ConstrainValueAfterCheckArrayBound( 291 void RangeAnalysis::ConstrainValueAfterCheckArrayBound(
268 Definition* defn, CheckArrayBoundInstr* check, intptr_t use_index) { 292 Value* use,
293 Definition* defn) {
294 CheckArrayBoundInstr* check = use->instruction()->AsCheckArrayBound();
295 intptr_t use_index = use->use_index();
296
269 Range* constraint_range = NULL; 297 Range* constraint_range = NULL;
270 if (use_index == CheckArrayBoundInstr::kIndexPos) { 298 if (use_index == CheckArrayBoundInstr::kIndexPos) {
271 Definition* length = check->length()->definition(); 299 Definition* length = check->length()->definition();
272 constraint_range = new(I) Range( 300 constraint_range = new(I) Range(
273 RangeBoundary::FromConstant(0), 301 RangeBoundary::FromConstant(0),
274 RangeBoundary::FromDefinition(length, -1)); 302 RangeBoundary::FromDefinition(length, -1));
275 } else { 303 } else {
276 ASSERT(use_index == CheckArrayBoundInstr::kLengthPos); 304 ASSERT(use_index == CheckArrayBoundInstr::kLengthPos);
277 Definition* index = check->index()->definition(); 305 Definition* index = check->index()->definition();
278 constraint_range = new(I) Range( 306 constraint_range = new(I) Range(
279 RangeBoundary::FromDefinition(index, 1), 307 RangeBoundary::FromDefinition(index, 1),
280 RangeBoundary::MaxSmi()); 308 RangeBoundary::MaxSmi());
281 } 309 }
282 InsertConstraintFor(defn, constraint_range, check); 310 InsertConstraintFor(use, defn, constraint_range, check);
283 } 311 }
284 312
285 313
286 void RangeAnalysis::InsertConstraints() { 314 void RangeAnalysis::InsertConstraints() {
287 for (intptr_t i = 0; i < smi_checks_.length(); i++) {
288 CheckSmiInstr* check = smi_checks_[i];
289 ConstraintInstr* constraint =
290 InsertConstraintFor(check->value()->definition(),
291 Range::UnknownSmi(),
292 check);
293 if (constraint == NULL) {
294 // No constraint was needed.
295 continue;
296 }
297 // Mark the constraint's value's reaching type as smi.
298 CompileType* smi_compile_type =
299 ZoneCompileType::Wrap(CompileType::FromCid(kSmiCid));
300 constraint->value()->SetReachingType(smi_compile_type);
301 }
302
303 for (intptr_t i = 0; i < values_.length(); i++) { 315 for (intptr_t i = 0; i < values_.length(); i++) {
304 InsertConstraintsFor(values_[i]); 316 InsertConstraintsFor(values_[i]);
305 } 317 }
306 318
307 for (intptr_t i = 0; i < constraints_.length(); i++) { 319 for (intptr_t i = 0; i < constraints_.length(); i++) {
308 InsertConstraintsFor(constraints_[i]); 320 InsertConstraintsFor(constraints_[i]);
309 } 321 }
310 } 322 }
311 323
312 324
313 void RangeAnalysis::ResetWorklist() { 325 const Range* RangeAnalysis::GetRange(Value* value) const {
314 if (marked_defns_ == NULL) { 326 Definition* defn = value->definition();
315 marked_defns_ = new(I) BitVector(flow_graph_->current_ssa_temp_index()); 327 const Range* range = defn->range();
316 } else { 328
317 marked_defns_->Clear(); 329 if ((range == NULL) &&
318 } 330 (value->Type()->ToCid() == kSmiCid) &&
319 worklist_.Clear(); 331 (defn->Type()->ToCid() != kSmiCid)) {
Florian Schneider 2014/08/18 10:46:51 Add mint cid here.
Vyacheslav Egorov (Google) 2014/08/18 10:58:19 All Mint values are defined by UnboxInteger instru
320 } 332 // Type propagator determined that reaching type for this use is Smi.
321 333 // However the definition itself is not a smi-definition and
322 334 // thus it will never have range assigned to it. Just return the widest
323 void RangeAnalysis::MarkDefinition(Definition* defn) { 335 // range possible for this value.
324 // Unwrap constrained value. 336 // Note: that we can't return NULL here because it is used as lattice's
337 // bottom element to indicate that the range was not computed *yet*.
338 return &smi_range_;
339 }
340
341 return range;
342 }
343
344
345 static Definition* UnwrapConstraint(Definition* defn) {
325 while (defn->IsConstraint()) { 346 while (defn->IsConstraint()) {
326 defn = defn->AsConstraint()->value()->definition(); 347 defn = defn->AsConstraint()->value()->definition();
327 } 348 }
328 349 return defn;
329 if (!marked_defns_->Contains(defn->ssa_temp_index())) { 350 }
330 worklist_.Add(defn); 351
331 marked_defns_->Add(defn->ssa_temp_index()); 352
332 } 353 static bool AreEqualDefinitions(Definition* a, Definition* b) {
333 } 354 a = UnwrapConstraint(a);
334 355 b = UnwrapConstraint(b);
335 356 return (a == b) ||
336 RangeAnalysis::Direction RangeAnalysis::ToDirection(Value* val) { 357 (a->AllowsCSE() &&
337 if (val->BindsToConstant()) { 358 a->Dependencies().IsNone() &&
338 return (Smi::Cast(val->BoundConstant()).Value() >= 0) ? kPositive 359 b->AllowsCSE() &&
339 : kNegative; 360 b->Dependencies().IsNone() &&
340 } else if (val->definition()->range() != NULL) { 361 a->Equals(b));
341 Range* range = val->definition()->range(); 362 }
342 if (Range::ConstantMin(range).ConstantValue() >= 0) { 363
343 return kPositive; 364
344 } else if (Range::ConstantMax(range).ConstantValue() <= 0) { 365 static bool DependOnSameSymbol(const RangeBoundary& a, const RangeBoundary& b) {
345 return kNegative; 366 return a.IsSymbol() && b.IsSymbol() &&
346 } 367 AreEqualDefinitions(a.symbol(), b.symbol());
347 } 368 }
348 return kUnknown; 369
349 } 370
350 371 // Given the current range of a phi and a newly computed range check
351 372 // if it is growing towards negative infinity, if it does widen it to
352 Range* RangeAnalysis::InferInductionVariableRange(JoinEntryInstr* loop_header, 373 // MinSmi.
353 PhiInstr* var) { 374 static RangeBoundary WidenMin(const Range* range, const Range* new_range) {
354 BitVector* loop_info = loop_header->loop_info(); 375 RangeBoundary min = range->min();
355 376 RangeBoundary new_min = new_range->min();
356 Definition* initial_value = NULL; 377
357 Direction direction = kUnknown; 378 if (min.IsSymbol()) {
358 379 if (min.LowerBound().OverflowedSmi()) {
359 ResetWorklist(); 380 return RangeBoundary::MinSmi();
360 MarkDefinition(var); 381 } else if (DependOnSameSymbol(min, new_min)) {
361 while (!worklist_.is_empty()) { 382 return min.offset() <= new_min.offset() ? min : RangeBoundary::MinSmi();
362 Definition* defn = worklist_.RemoveLast(); 383 } else if (min.SmiUpperBound() <= new_min.SmiLowerBound()) {
363 384 return min;
364 if (defn->IsPhi()) { 385 }
365 PhiInstr* phi = defn->AsPhi(); 386 }
366 for (intptr_t i = 0; i < phi->InputCount(); i++) { 387
367 Definition* defn = phi->InputAt(i)->definition(); 388 min = Range::ConstantMinSmi(range);
368 389 new_min = Range::ConstantMinSmi(new_range);
369 if (!loop_info->Contains(defn->GetBlock()->preorder_number())) { 390
370 // The value is coming from outside of the loop. 391 return (min.ConstantValue() <= new_min.ConstantValue()) ?
371 if (initial_value == NULL) { 392 min : RangeBoundary::MinSmi();
372 initial_value = defn; 393 }
373 continue; 394
374 } else if (initial_value == defn) { 395 // Given the current range of a phi and a newly computed range check
375 continue; 396 // if it is growing towards positive infinity, if it does widen it to
376 } else { 397 // MaxSmi.
377 return NULL; 398 static RangeBoundary WidenMax(const Range* range, const Range* new_range) {
378 } 399 RangeBoundary max = range->max();
400 RangeBoundary new_max = new_range->max();
401
402 if (max.IsSymbol()) {
403 if (max.UpperBound().OverflowedSmi()) {
404 return RangeBoundary::MaxSmi();
405 } else if (DependOnSameSymbol(max, new_max)) {
406 return max.offset() >= new_max.offset() ? max : RangeBoundary::MaxSmi();
407 } else if (max.SmiLowerBound() >= new_max.SmiUpperBound()) {
408 return max;
409 }
410 }
411
412 max = Range::ConstantMaxSmi(range);
413 new_max = Range::ConstantMaxSmi(new_range);
414
415 return (max.ConstantValue() >= new_max.ConstantValue()) ?
416 max : RangeBoundary::MaxSmi();
417 }
418
419
420 // Given the current range of a phi and a newly computed range check
421 // if we can perform narrowing: use newly computed minimum to improve precision
422 // of the computed range. We do it only if current minimum was widened and is
423 // equal to MinSmi.
424 // Newly computed minimum is expected to be greater of equal then old one as
425 // we are running after widening phase.
426 static RangeBoundary NarrowMin(const Range* range, const Range* new_range) {
427 #ifdef DEBUG
428 const RangeBoundary min = Range::ConstantMinSmi(range);
429 const RangeBoundary new_min = Range::ConstantMinSmi(new_range);
430 ASSERT(min.ConstantValue() <= new_min.ConstantValue());
431 #endif
432 // TODO(vegorov): consider using negative infinity to indicate widened bound.
433 return range->min().IsSmiMinimumOrBelow() ? new_range->min() : range->min();
434 }
435
436
437 // Given the current range of a phi and a newly computed range check
438 // if we can perform narrowing: use newly computed maximum to improve precision
439 // of the computed range. We do it only if current maximum was widened and is
440 // equal to MaxSmi.
441 // Newly computed minimum is expected to be greater of equal then old one as
442 // we are running after widening phase.
443 static RangeBoundary NarrowMax(const Range* range, const Range* new_range) {
444 #ifdef DEBUG
445 const RangeBoundary max = Range::ConstantMaxSmi(range);
446 const RangeBoundary new_max = Range::ConstantMaxSmi(new_range);
447 ASSERT(max.ConstantValue() >= new_max.ConstantValue());
448 #endif
449 // TODO(vegorov): consider using positive infinity to indicate widened bound.
450 return range->max().IsSmiMaximumOrAbove() ? new_range->max() : range->max();
451 }
452
453
454 char RangeAnalysis::OpPrefix(JoinOperator op) {
455 switch (op) {
456 case WIDEN: return 'W';
457 case NARROW: return 'N';
458 case NONE: return 'I';
459 }
460 UNREACHABLE();
461 return ' ';
462 }
463
464
465 bool RangeAnalysis::InferRange(JoinOperator op,
466 Definition* defn,
467 intptr_t iteration) {
468 Range range;
469 defn->InferRange(this, &range);
470
471 if (!Range::IsUnknown(&range)) {
472 if (!Range::IsUnknown(defn->range()) && defn->IsPhi()) {
473 // TODO(vegorov): we are currently supporting only smi phis.
474 ASSERT(defn->Type()->ToCid() == kSmiCid);
475 if (op == WIDEN) {
476 range = Range(WidenMin(defn->range(), &range),
477 WidenMax(defn->range(), &range));
478 } else if (op == NARROW) {
479 range = Range(NarrowMin(defn->range(), &range),
480 NarrowMax(defn->range(), &range));
481 }
482 }
483
484 if (!range.Equals(defn->range())) {
485 if (FLAG_trace_range_analysis) {
486 OS::Print("%c [%" Pd "] %s: %s => %s\n",
487 OpPrefix(op),
488 iteration,
489 defn->ToCString(),
490 Range::ToCString(defn->range()),
491 Range::ToCString(&range));
492 }
493 defn->set_range(range);
494 return true;
495 }
496 }
497
498 return false;
499 }
500
501
502 void RangeAnalysis::CollectDefinitions(BlockEntryInstr* block, BitVector* set) {
503 for (BlockIterator block_it = flow_graph_->reverse_postorder_iterator();
504 !block_it.Done();
505 block_it.Advance()) {
506 BlockEntryInstr* block = block_it.Current();
507
508 JoinEntryInstr* join = block->AsJoinEntry();
509 if (join != NULL) {
510 for (PhiIterator it(join); !it.Done(); it.Advance()) {
511 PhiInstr* phi = it.Current();
512 if (set->Contains(phi->ssa_temp_index())) {
513 definitions_.Add(phi);
379 } 514 }
380 515 }
381 MarkDefinition(defn); 516 }
382 } 517
383 } else if (defn->IsBinarySmiOp()) { 518 for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) {
384 BinarySmiOpInstr* binary_op = defn->AsBinarySmiOp(); 519 Definition* defn = it.Current()->AsDefinition();
385 520 if ((defn != NULL) &&
386 switch (binary_op->op_kind()) { 521 (defn->ssa_temp_index() != -1) &&
387 case Token::kADD: { 522 set->Contains(defn->ssa_temp_index())) {
388 const Direction growth_right = 523 definitions_.Add(defn);
389 ToDirection(binary_op->right()); 524 }
390 if (growth_right != kUnknown) { 525 }
391 UpdateDirection(&direction, growth_right); 526 }
392 MarkDefinition(binary_op->left()->definition()); 527 }
393 break; 528
394 } 529
395 530 void RangeAnalysis::Iterate(JoinOperator op, intptr_t max_iterations) {
396 const Direction growth_left = 531 // TODO(vegorov): switch to worklist if this becomes performance bottleneck.
397 ToDirection(binary_op->left()); 532 intptr_t iteration = 0;
398 if (growth_left != kUnknown) { 533 bool changed;
399 UpdateDirection(&direction, growth_left); 534 do {
400 MarkDefinition(binary_op->right()->definition()); 535 changed = false;
401 break; 536 for (intptr_t i = 0; i < definitions_.length(); i++) {
402 } 537 Definition* defn = definitions_[i];
403 538 if (InferRange(op, defn, iteration)) {
404 return NULL; 539 changed = true;
405 } 540 }
406 541 }
407 case Token::kSUB: { 542
408 const Direction growth_right = 543 iteration++;
409 ToDirection(binary_op->right()); 544 } while (changed && (iteration < max_iterations));
410 if (growth_right != kUnknown) {
411 UpdateDirection(&direction, Invert(growth_right));
412 MarkDefinition(binary_op->left()->definition());
413 break;
414 }
415 return NULL;
416 }
417
418 default:
419 return NULL;
420 }
421 } else {
422 return NULL;
423 }
424 }
425
426
427 // We transitively discovered all dependencies of the given phi
428 // and confirmed that it depends on a single value coming from outside of
429 // the loop and some linear combinations of itself.
430 // Compute the range based on initial value and the direction of the growth.
431 switch (direction) {
432 case kPositive:
433 return new(I) Range(RangeBoundary::FromDefinition(initial_value),
434 RangeBoundary::MaxSmi());
435
436 case kNegative:
437 return new(I) Range(RangeBoundary::MinSmi(),
438 RangeBoundary::FromDefinition(initial_value));
439
440 case kUnknown:
441 case kBoth:
442 return Range::UnknownSmi();
443 }
444
445 UNREACHABLE();
446 return NULL;
447 }
448
449
450 void RangeAnalysis::InferRangesRecursive(BlockEntryInstr* block) {
451 JoinEntryInstr* join = block->AsJoinEntry();
452 if (join != NULL) {
453 const bool is_loop_header = (join->loop_info() != NULL);
454 for (PhiIterator it(join); !it.Done(); it.Advance()) {
455 PhiInstr* phi = it.Current();
456 if (definitions_->Contains(phi->ssa_temp_index())) {
457 if (is_loop_header) {
458 // Try recognizing simple induction variables.
459 Range* range = InferInductionVariableRange(join, phi);
460 if (range != NULL) {
461 phi->range_ = range;
462 continue;
463 }
464 }
465
466 phi->InferRange();
467 }
468 }
469 }
470
471 for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) {
472 Instruction* current = it.Current();
473
474 Definition* defn = current->AsDefinition();
475 if ((defn != NULL) &&
476 (defn->ssa_temp_index() != -1) &&
477 definitions_->Contains(defn->ssa_temp_index())) {
478 defn->InferRange();
479 } else if (FLAG_array_bounds_check_elimination &&
480 current->IsCheckArrayBound()) {
481 CheckArrayBoundInstr* check = current->AsCheckArrayBound();
482 RangeBoundary array_length =
483 RangeBoundary::FromDefinition(check->length()->definition());
484 if (check->IsRedundant(array_length)) {
485 it.RemoveCurrentFromGraph();
486 }
487 }
488 }
489
490 for (intptr_t i = 0; i < block->dominated_blocks().length(); ++i) {
491 InferRangesRecursive(block->dominated_blocks()[i]);
492 }
493 } 545 }
494 546
495 547
496 void RangeAnalysis::InferRanges() { 548 void RangeAnalysis::InferRanges() {
497 if (FLAG_trace_range_analysis) { 549 if (FLAG_trace_range_analysis) {
498 OS::Print("---- before range analysis -------\n"); 550 FlowGraphPrinter::PrintGraph("Range Analysis (BEFORE)", flow_graph_);
499 FlowGraphPrinter printer(*flow_graph_); 551 }
500 printer.PrintBlocks(); 552
501 }
502 // Initialize bitvector for quick filtering of int values. 553 // Initialize bitvector for quick filtering of int values.
503 definitions_ = 554 BitVector* set = new(I) BitVector(flow_graph_->current_ssa_temp_index());
504 new(I) BitVector(flow_graph_->current_ssa_temp_index());
505 for (intptr_t i = 0; i < values_.length(); i++) { 555 for (intptr_t i = 0; i < values_.length(); i++) {
506 definitions_->Add(values_[i]->ssa_temp_index()); 556 set->Add(values_[i]->ssa_temp_index());
507 } 557 }
508 for (intptr_t i = 0; i < constraints_.length(); i++) { 558 for (intptr_t i = 0; i < constraints_.length(); i++) {
509 definitions_->Add(constraints_[i]->ssa_temp_index()); 559 set->Add(constraints_[i]->ssa_temp_index());
510 } 560 }
511 561
512 // Infer initial values of ranges. 562 // Collect integer definitions (including constraints) in the reverse
563 // postorder. This improves convergence speed compared to iterating
564 // values_ and constraints_ array separately.
513 const GrowableArray<Definition*>& initial = 565 const GrowableArray<Definition*>& initial =
514 *flow_graph_->graph_entry()->initial_definitions(); 566 *flow_graph_->graph_entry()->initial_definitions();
515 for (intptr_t i = 0; i < initial.length(); ++i) { 567 for (intptr_t i = 0; i < initial.length(); ++i) {
516 Definition* definition = initial[i]; 568 Definition* definition = initial[i];
517 if (definitions_->Contains(definition->ssa_temp_index())) { 569 if (set->Contains(definition->ssa_temp_index())) {
518 definition->InferRange(); 570 definitions_.Add(definition);
519 } 571 }
520 } 572 }
521 InferRangesRecursive(flow_graph_->graph_entry()); 573 CollectDefinitions(flow_graph_->graph_entry(), set);
574
575 // Perform an iteration of range inference just propagating ranges
576 // through the graph as-is without applying widening or narrowing.
577 // This helps to improve precision of initial bounds.
578 Iterate(NONE, 1);
579
580 // Perform fix-point iteration of range inference applying widening
581 // operator to phis to ensure fast convergence.
582 // Widening simply maps growing bounds to the respective range bound.
583 Iterate(WIDEN, kMaxInt32);
522 584
523 if (FLAG_trace_range_analysis) { 585 if (FLAG_trace_range_analysis) {
524 OS::Print("---- after range analysis -------\n"); 586 FlowGraphPrinter::PrintGraph("Range Analysis (WIDEN)", flow_graph_);
525 FlowGraphPrinter printer(*flow_graph_); 587 }
526 printer.PrintBlocks(); 588
527 } 589 // Perform fix-point iteration of range inference applying narrowing
528 } 590 // to phis to compute more accurate range.
529 591 // Narrowing only improves those boundaries that were widened up to
592 // range boundary and leaves other boundaries intact.
593 Iterate(NARROW, kMaxInt32);
594
595 if (FLAG_trace_range_analysis) {
596 FlowGraphPrinter::PrintGraph("Range Analysis (AFTER)", flow_graph_);
597 }
598 }
599
600
601 void RangeAnalysis::EliminateRedundantBoundsChecks() {
602 if (FLAG_array_bounds_check_elimination) {
603 for (intptr_t i = 0; i < bounds_checks_.length(); i++) {
604 CheckArrayBoundInstr* check = bounds_checks_[i];
605 RangeBoundary array_length =
606 RangeBoundary::FromDefinition(check->length()->definition());
607 if (check->IsRedundant(array_length)) {
608 check->RemoveFromGraph();
609 }
610 }
611 }
612 }
613
614
615 void RangeAnalysis::MarkUnreachableBlocks() {
616 for (intptr_t i = 0; i < constraints_.length(); i++) {
617 if (Range::IsUnknown(constraints_[i]->range())) {
618 TargetEntryInstr* target = constraints_[i]->target();
619 if (target == NULL) {
620 // TODO(vegorov): replace Constraint with an uncoditional
621 // deoptimization and kill all dominated dead code.
622 continue;
623 }
624
625 BranchInstr* branch =
626 target->PredecessorAt(0)->last_instruction()->AsBranch();
627 if (target == branch->true_successor()) {
628 // True unreachable.
629 if (FLAG_trace_constant_propagation) {
630 OS::Print("Range analysis: True unreachable (B%" Pd ")\n",
631 branch->true_successor()->block_id());
632 }
633 branch->set_constant_target(branch->false_successor());
634 } else {
635 ASSERT(target == branch->false_successor());
636 // False unreachable.
637 if (FLAG_trace_constant_propagation) {
638 OS::Print("Range analysis: False unreachable (B%" Pd ")\n",
639 branch->false_successor()->block_id());
640 }
641 branch->set_constant_target(branch->true_successor());
642 }
643 }
644 }
645 }
646
530 647
531 void RangeAnalysis::RemoveConstraints() { 648 void RangeAnalysis::RemoveConstraints() {
532 for (intptr_t i = 0; i < constraints_.length(); i++) { 649 for (intptr_t i = 0; i < constraints_.length(); i++) {
533 Definition* def = constraints_[i]->value()->definition(); 650 Definition* def = constraints_[i]->value()->definition();
534 // Some constraints might be constraining constraints. Unwind the chain of 651 // Some constraints might be constraining constraints. Unwind the chain of
535 // constraints until we reach the actual definition. 652 // constraints until we reach the actual definition.
536 while (def->IsConstraint()) { 653 while (def->IsConstraint()) {
537 def = def->AsConstraint()->value()->definition(); 654 def = def->AsConstraint()->value()->definition();
538 } 655 }
539 constraints_[i]->ReplaceUsesWith(def); 656 constraints_[i]->ReplaceUsesWith(def);
(...skipping 260 matching lines...) Expand 10 before | Expand all | Expand 10 after
800 } 917 }
801 return RangeBoundary(kSymbol, reinterpret_cast<intptr_t>(defn), offs); 918 return RangeBoundary(kSymbol, reinterpret_cast<intptr_t>(defn), offs);
802 } 919 }
803 920
804 921
805 RangeBoundary RangeBoundary::LowerBound() const { 922 RangeBoundary RangeBoundary::LowerBound() const {
806 if (IsInfinity()) { 923 if (IsInfinity()) {
807 return NegativeInfinity(); 924 return NegativeInfinity();
808 } 925 }
809 if (IsConstant()) return *this; 926 if (IsConstant()) return *this;
810 return Add(Range::ConstantMin(symbol()->range()), 927 return Add(Range::ConstantMinSmi(symbol()->range()),
811 RangeBoundary::FromConstant(offset_), 928 RangeBoundary::FromConstant(offset_),
812 NegativeInfinity()); 929 NegativeInfinity());
813 } 930 }
814 931
815 932
816 RangeBoundary RangeBoundary::UpperBound() const { 933 RangeBoundary RangeBoundary::UpperBound() const {
817 if (IsInfinity()) { 934 if (IsInfinity()) {
818 return PositiveInfinity(); 935 return PositiveInfinity();
819 } 936 }
820 if (IsConstant()) return *this; 937 if (IsConstant()) return *this;
821 return Add(Range::ConstantMax(symbol()->range()), 938
939 return Add(Range::ConstantMaxSmi(symbol()->range()),
822 RangeBoundary::FromConstant(offset_), 940 RangeBoundary::FromConstant(offset_),
823 PositiveInfinity()); 941 PositiveInfinity());
824 } 942 }
825 943
826 944
827 RangeBoundary RangeBoundary::Add(const RangeBoundary& a, 945 RangeBoundary RangeBoundary::Add(const RangeBoundary& a,
828 const RangeBoundary& b, 946 const RangeBoundary& b,
829 const RangeBoundary& overflow) { 947 const RangeBoundary& overflow) {
830 if (a.IsInfinity() || b.IsInfinity()) return overflow; 948 if (a.IsInfinity() || b.IsInfinity()) return overflow;
831 949
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
884 1002
885 const int64_t offset = a.offset() - b.ConstantValue(); 1003 const int64_t offset = a.offset() - b.ConstantValue();
886 1004
887 *result = RangeBoundary::FromDefinition(a.symbol(), offset); 1005 *result = RangeBoundary::FromDefinition(a.symbol(), offset);
888 return true; 1006 return true;
889 } 1007 }
890 return false; 1008 return false;
891 } 1009 }
892 1010
893 1011
894 static Definition* UnwrapConstraint(Definition* defn) {
895 while (defn->IsConstraint()) {
896 defn = defn->AsConstraint()->value()->definition();
897 }
898 return defn;
899 }
900
901
902 static bool AreEqualDefinitions(Definition* a, Definition* b) {
903 a = UnwrapConstraint(a);
904 b = UnwrapConstraint(b);
905 return (a == b) ||
906 (a->AllowsCSE() &&
907 a->Dependencies().IsNone() &&
908 b->AllowsCSE() &&
909 b->Dependencies().IsNone() &&
910 a->Equals(b));
911 }
912
913
914 // Returns true if two range boundaries refer to the same symbol.
915 static bool DependOnSameSymbol(const RangeBoundary& a, const RangeBoundary& b) {
916 return a.IsSymbol() && b.IsSymbol() &&
917 AreEqualDefinitions(a.symbol(), b.symbol());
918 }
919
920
921 bool RangeBoundary::Equals(const RangeBoundary& other) const { 1012 bool RangeBoundary::Equals(const RangeBoundary& other) const {
922 if (IsConstant() && other.IsConstant()) { 1013 if (IsConstant() && other.IsConstant()) {
923 return ConstantValue() == other.ConstantValue(); 1014 return ConstantValue() == other.ConstantValue();
924 } else if (IsInfinity() && other.IsInfinity()) { 1015 } else if (IsInfinity() && other.IsInfinity()) {
925 return kind() == other.kind(); 1016 return kind() == other.kind();
926 } else if (IsSymbol() && other.IsSymbol()) { 1017 } else if (IsSymbol() && other.IsSymbol()) {
927 return (offset() == other.offset()) && DependOnSameSymbol(*this, other); 1018 return (offset() == other.offset()) && DependOnSameSymbol(*this, other);
928 } else if (IsUnknown() && other.IsUnknown()) { 1019 } else if (IsUnknown() && other.IsUnknown()) {
929 return true; 1020 return true;
930 } 1021 }
(...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after
1050 1141
1051 const int64_t offset = range->min().offset() + a->offset(); 1142 const int64_t offset = range->min().offset() + a->offset();
1052 1143
1053 *a = CanonicalizeBoundary( 1144 *a = CanonicalizeBoundary(
1054 RangeBoundary::FromDefinition(range->min().symbol(), offset), 1145 RangeBoundary::FromDefinition(range->min().symbol(), offset),
1055 RangeBoundary::NegativeInfinity()); 1146 RangeBoundary::NegativeInfinity());
1056 1147
1057 return true; 1148 return true;
1058 } 1149 }
1059 1150
1151 typedef bool (*BoundaryOp)(RangeBoundary*);
1060 1152
1061 RangeBoundary RangeBoundary::Min(RangeBoundary a, RangeBoundary b, 1153 static bool CanonicalizeForComparison(RangeBoundary* a,
1062 RangeSize size) { 1154 RangeBoundary* b,
1063 ASSERT(!(a.IsNegativeInfinity() || b.IsNegativeInfinity())); 1155 BoundaryOp op,
1064 ASSERT(!a.IsUnknown() || !b.IsUnknown()); 1156 const RangeBoundary& overflow) {
1065 if (a.IsUnknown() && !b.IsUnknown()) { 1157 if (!a->IsSymbol() || !b->IsSymbol()) {
1066 return b; 1158 return false;
1067 }
1068 if (!a.IsUnknown() && b.IsUnknown()) {
1069 return a;
1070 }
1071 if (size == kRangeBoundarySmi) {
1072 if (a.IsSmiMaximumOrAbove() && !b.IsSmiMaximumOrAbove()) {
1073 return b;
1074 }
1075 if (!a.IsSmiMaximumOrAbove() && b.IsSmiMaximumOrAbove()) {
1076 return a;
1077 }
1078 } else {
1079 ASSERT(size == kRangeBoundaryInt64);
1080 if (a.IsMaximumOrAbove() && !b.IsMaximumOrAbove()) {
1081 return b;
1082 }
1083 if (!a.IsMaximumOrAbove() && b.IsMaximumOrAbove()) {
1084 return a;
1085 }
1086 } 1159 }
1087 1160
1161 if (DependOnSameSymbol(*a, *b)) {
1162 return true;
1163 }
1164
1165
1166 RangeBoundary canonical_a = CanonicalizeBoundary(*a, overflow);
1167 RangeBoundary canonical_b = CanonicalizeBoundary(*b, overflow);
1168
1169 do {
1170 if (DependOnSameSymbol(canonical_a, canonical_b)) {
1171 *a = canonical_a;
1172 *b = canonical_b;
1173 return true;
1174 }
1175 } while (op(&canonical_a) || op(&canonical_b));
1176
1177 return false;
1178 }
1179
1180
1181 RangeBoundary RangeBoundary::JoinMin(RangeBoundary a, RangeBoundary b) {
1088 if (a.Equals(b)) { 1182 if (a.Equals(b)) {
1089 return b; 1183 return b;
1090 } 1184 }
1091 1185
1092 { 1186 if (CanonicalizeForComparison(&a,
1093 RangeBoundary canonical_a = 1187 &b,
1094 CanonicalizeBoundary(a, RangeBoundary::PositiveInfinity()); 1188 &CanonicalizeMinBoundary,
1095 RangeBoundary canonical_b = 1189 RangeBoundary::NegativeInfinity())) {
1096 CanonicalizeBoundary(b, RangeBoundary::PositiveInfinity());
1097 do {
1098 if (DependOnSameSymbol(canonical_a, canonical_b)) {
1099 a = canonical_a;
1100 b = canonical_b;
1101 break;
1102 }
1103 } while (CanonicalizeMaxBoundary(&canonical_a) ||
1104 CanonicalizeMaxBoundary(&canonical_b));
1105 }
1106
1107 if (DependOnSameSymbol(a, b)) {
1108 return (a.offset() <= b.offset()) ? a : b; 1190 return (a.offset() <= b.offset()) ? a : b;
1109 } 1191 }
1110 1192
1111 const int64_t min_a = a.UpperBound().Clamp(size).ConstantValue(); 1193 const int64_t inf_a = a.SmiLowerBound();
1112 const int64_t min_b = b.UpperBound().Clamp(size).ConstantValue(); 1194 const int64_t inf_b = b.SmiLowerBound();
1195 const int64_t sup_a = a.SmiUpperBound();
1196 const int64_t sup_b = b.SmiUpperBound();
1113 1197
1114 return RangeBoundary::FromConstant(Utils::Minimum(min_a, min_b)); 1198 if ((sup_a <= inf_b) && !a.LowerBound().OverflowedSmi()) {
1199 return a;
1200 } else if ((sup_b <= inf_a) && !b.LowerBound().OverflowedSmi()) {
1201 return b;
1202 } else {
1203 return RangeBoundary::FromConstant(Utils::Minimum(inf_a, inf_b));
1204 }
1115 } 1205 }
1116 1206
1117 1207
1118 RangeBoundary RangeBoundary::Max(RangeBoundary a, RangeBoundary b, 1208 RangeBoundary RangeBoundary::JoinMax(RangeBoundary a, RangeBoundary b) {
1119 RangeSize size) {
1120 ASSERT(!(a.IsPositiveInfinity() || b.IsPositiveInfinity()));
1121 ASSERT(!a.IsUnknown() || !b.IsUnknown());
1122 if (a.IsUnknown() && !b.IsUnknown()) {
1123 return b;
1124 }
1125 if (!a.IsUnknown() && b.IsUnknown()) {
1126 return a;
1127 }
1128 if (size == kRangeBoundarySmi) {
1129 if (a.IsSmiMinimumOrBelow() && !b.IsSmiMinimumOrBelow()) {
1130 return b;
1131 }
1132 if (!a.IsSmiMinimumOrBelow() && b.IsSmiMinimumOrBelow()) {
1133 return a;
1134 }
1135 } else {
1136 ASSERT(size == kRangeBoundaryInt64);
1137 if (a.IsMinimumOrBelow() && !b.IsMinimumOrBelow()) {
1138 return b;
1139 }
1140 if (!a.IsMinimumOrBelow() && b.IsMinimumOrBelow()) {
1141 return a;
1142 }
1143 }
1144 if (a.Equals(b)) { 1209 if (a.Equals(b)) {
1145 return b; 1210 return b;
1146 } 1211 }
1147 1212
1148 { 1213 if (CanonicalizeForComparison(&a,
1149 RangeBoundary canonical_a = 1214 &b,
1150 CanonicalizeBoundary(a, RangeBoundary::NegativeInfinity()); 1215 &CanonicalizeMaxBoundary,
1151 RangeBoundary canonical_b = 1216 RangeBoundary::PositiveInfinity())) {
1152 CanonicalizeBoundary(b, RangeBoundary::NegativeInfinity()); 1217 return (a.offset() >= b.offset()) ? a : b;
1153
1154 do {
1155 if (DependOnSameSymbol(canonical_a, canonical_b)) {
1156 a = canonical_a;
1157 b = canonical_b;
1158 break;
1159 }
1160 } while (CanonicalizeMinBoundary(&canonical_a) ||
1161 CanonicalizeMinBoundary(&canonical_b));
1162 } 1218 }
1163 1219
1164 if (DependOnSameSymbol(a, b)) { 1220 const int64_t inf_a = a.SmiLowerBound();
1165 return (a.offset() <= b.offset()) ? b : a; 1221 const int64_t inf_b = b.SmiLowerBound();
1222 const int64_t sup_a = a.SmiUpperBound();
1223 const int64_t sup_b = b.SmiUpperBound();
1224
1225 if ((sup_a <= inf_b) && !b.UpperBound().OverflowedSmi()) {
1226 return b;
1227 } else if ((sup_b <= inf_a) && !a.UpperBound().OverflowedSmi()) {
1228 return a;
1229 } else {
1230 return RangeBoundary::FromConstant(Utils::Maximum(sup_a, sup_b));
1166 } 1231 }
1167
1168 const int64_t max_a = a.LowerBound().Clamp(size).ConstantValue();
1169 const int64_t max_b = b.LowerBound().Clamp(size).ConstantValue();
1170
1171 return RangeBoundary::FromConstant(Utils::Maximum(max_a, max_b));
1172 } 1232 }
1173 1233
1174 1234
1235 RangeBoundary RangeBoundary::IntersectionMin(RangeBoundary a, RangeBoundary b) {
1236 ASSERT(!a.IsPositiveInfinity() && !b.IsPositiveInfinity());
1237 ASSERT(!a.IsUnknown() && !b.IsUnknown());
1238
1239 if (a.Equals(b)) {
1240 return a;
1241 }
1242
1243 if (a.IsSmiMinimumOrBelow()) {
1244 return b;
1245 } else if (b.IsSmiMinimumOrBelow()) {
1246 return a;
1247 }
1248
1249 if (CanonicalizeForComparison(&a,
1250 &b,
1251 &CanonicalizeMinBoundary,
1252 RangeBoundary::NegativeInfinity())) {
1253 return (a.offset() >= b.offset()) ? a : b;
1254 }
1255
1256 const int64_t inf_a = a.SmiLowerBound();
1257 const int64_t inf_b = b.SmiLowerBound();
1258
1259 return (inf_a >= inf_b) ? a : b;
1260 }
1261
1262
1263 RangeBoundary RangeBoundary::IntersectionMax(RangeBoundary a, RangeBoundary b) {
1264 ASSERT(!a.IsNegativeInfinity() && !b.IsNegativeInfinity());
1265 ASSERT(!a.IsUnknown() && !b.IsUnknown());
1266
1267 if (a.Equals(b)) {
1268 return a;
1269 }
1270
1271 if (a.IsSmiMaximumOrAbove()) {
1272 return b;
1273 } else if (b.IsSmiMaximumOrAbove()) {
1274 return a;
1275 }
1276
1277 if (CanonicalizeForComparison(&a,
1278 &b,
1279 &CanonicalizeMaxBoundary,
1280 RangeBoundary::PositiveInfinity())) {
1281 return (a.offset() <= b.offset()) ? a : b;
1282 }
1283
1284 const int64_t sup_a = a.SmiUpperBound();
1285 const int64_t sup_b = b.SmiUpperBound();
1286
1287 return (sup_a <= sup_b) ? a : b;
1288 }
1289
1290
1175 int64_t RangeBoundary::ConstantValue() const { 1291 int64_t RangeBoundary::ConstantValue() const {
1176 ASSERT(IsConstant()); 1292 ASSERT(IsConstant());
1177 return value_; 1293 return value_;
1178 } 1294 }
1179 1295
1180 1296
1181 bool Range::IsPositive() const { 1297 bool Range::IsPositive() const {
1182 if (min().IsNegativeInfinity()) { 1298 if (min().IsNegativeInfinity()) {
1183 return false; 1299 return false;
1184 } 1300 }
(...skipping 161 matching lines...) Expand 10 before | Expand all | Expand 10 after
1346 } 1462 }
1347 1463
1348 return false; 1464 return false;
1349 } 1465 }
1350 1466
1351 1467
1352 static bool IsArrayLength(Definition* defn) { 1468 static bool IsArrayLength(Definition* defn) {
1353 if (defn == NULL) { 1469 if (defn == NULL) {
1354 return false; 1470 return false;
1355 } 1471 }
1356 LoadFieldInstr* load = defn->AsLoadField(); 1472 LoadFieldInstr* load = UnwrapConstraint(defn)->AsLoadField();
1357 return (load != NULL) && load->IsImmutableLengthLoad(); 1473 return (load != NULL) && load->IsImmutableLengthLoad();
1358 } 1474 }
1359 1475
1360 1476
1361 void Range::Add(const Range* left_range, 1477 void Range::Add(const Range* left_range,
1362 const Range* right_range, 1478 const Range* right_range,
1363 RangeBoundary* result_min, 1479 RangeBoundary* result_min,
1364 RangeBoundary* result_max, 1480 RangeBoundary* result_max,
1365 Definition* left_defn) { 1481 Definition* left_defn) {
1366 ASSERT(left_range != NULL); 1482 ASSERT(left_range != NULL);
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after
1438 if (Smi::IsValid(mul_max) && Smi::IsValid(-mul_max)) { 1554 if (Smi::IsValid(mul_max) && Smi::IsValid(-mul_max)) {
1439 const int64_t r_min = 1555 const int64_t r_min =
1440 OnlyPositiveOrZero(*left_range, *right_range) ? 0 : -mul_max; 1556 OnlyPositiveOrZero(*left_range, *right_range) ? 0 : -mul_max;
1441 *result_min = RangeBoundary::FromConstant(r_min); 1557 *result_min = RangeBoundary::FromConstant(r_min);
1442 const int64_t r_max = 1558 const int64_t r_max =
1443 OnlyNegativeOrZero(*left_range, *right_range) ? 0 : mul_max; 1559 OnlyNegativeOrZero(*left_range, *right_range) ? 0 : mul_max;
1444 *result_max = RangeBoundary::FromConstant(r_max); 1560 *result_max = RangeBoundary::FromConstant(r_max);
1445 return true; 1561 return true;
1446 } 1562 }
1447 } 1563 }
1564
1565 // TODO(vegorov): handle mixed sign case that leads to (-Infinity, 0] range.
1566 if (OnlyPositiveOrZero(*left_range, *right_range) ||
1567 OnlyNegativeOrZero(*left_range, *right_range)) {
1568 *result_min = RangeBoundary::FromConstant(0);
1569 *result_max = RangeBoundary::PositiveInfinity();
1570 return true;
1571 }
1572
1448 return false; 1573 return false;
1449 } 1574 }
1450 1575
1451 1576
1452 // Both the a and b ranges are >= 0. 1577 // Both the a and b ranges are >= 0.
1453 bool Range::OnlyPositiveOrZero(const Range& a, const Range& b) { 1578 bool Range::OnlyPositiveOrZero(const Range& a, const Range& b) {
1454 return a.OnlyGreaterThanOrEqualTo(0) && b.OnlyGreaterThanOrEqualTo(0); 1579 return a.OnlyGreaterThanOrEqualTo(0) && b.OnlyGreaterThanOrEqualTo(0);
1455 } 1580 }
1456 1581
1457 1582
1458 // Both the a and b ranges are <= 0. 1583 // Both the a and b ranges are <= 0.
1459 bool Range::OnlyNegativeOrZero(const Range& a, const Range& b) { 1584 bool Range::OnlyNegativeOrZero(const Range& a, const Range& b) {
1460 return a.OnlyLessThanOrEqualTo(0) && b.OnlyLessThanOrEqualTo(0); 1585 return a.OnlyLessThanOrEqualTo(0) && b.OnlyLessThanOrEqualTo(0);
1461 } 1586 }
1462 1587
1463 1588
1464 // Return the maximum absolute value included in range. 1589 // Return the maximum absolute value included in range.
1465 int64_t Range::ConstantAbsMax(const Range* range) { 1590 int64_t Range::ConstantAbsMax(const Range* range) {
1466 if (range == NULL) { 1591 if (range == NULL) {
1467 return RangeBoundary::kMax; 1592 return RangeBoundary::kMax;
1468 } 1593 }
1469 const int64_t abs_min = Utils::Abs(Range::ConstantMin(range).ConstantValue()); 1594 const int64_t abs_min = Utils::Abs(Range::ConstantMin(range).ConstantValue());
1470 const int64_t abs_max = Utils::Abs(Range::ConstantMax(range).ConstantValue()); 1595 const int64_t abs_max = Utils::Abs(Range::ConstantMax(range).ConstantValue());
1471 return Utils::Maximum(abs_min, abs_max); 1596 return Utils::Maximum(abs_min, abs_max);
1472 } 1597 }
1473 1598
1474 1599
1475 Range* Range::BinaryOp(const Token::Kind op, 1600 void Range::BinaryOp(const Token::Kind op,
1476 const Range* left_range, 1601 const Range* left_range,
1477 const Range* right_range, 1602 const Range* right_range,
1478 Definition* left_defn) { 1603 Definition* left_defn,
1604 Range* result) {
1479 ASSERT(left_range != NULL); 1605 ASSERT(left_range != NULL);
1480 ASSERT(right_range != NULL); 1606 ASSERT(right_range != NULL);
1481 1607
1482 // Both left and right ranges are finite. 1608 // Both left and right ranges are finite.
1483 ASSERT(left_range->IsFinite()); 1609 ASSERT(left_range->IsFinite());
1484 ASSERT(right_range->IsFinite()); 1610 ASSERT(right_range->IsFinite());
1485 1611
1486 RangeBoundary min; 1612 RangeBoundary min;
1487 RangeBoundary max; 1613 RangeBoundary max;
1488 ASSERT(min.IsUnknown() && max.IsUnknown()); 1614 ASSERT(min.IsUnknown() && max.IsUnknown());
1489 1615
1490 switch (op) { 1616 switch (op) {
1491 case Token::kADD: 1617 case Token::kADD:
1492 Range::Add(left_range, right_range, &min, &max, left_defn); 1618 Range::Add(left_range, right_range, &min, &max, left_defn);
1493 break; 1619 break;
1494 case Token::kSUB: 1620 case Token::kSUB:
1495 Range::Sub(left_range, right_range, &min, &max, left_defn); 1621 Range::Sub(left_range, right_range, &min, &max, left_defn);
1496 break; 1622 break;
1497 case Token::kMUL: { 1623 case Token::kMUL: {
1498 if (!Range::Mul(left_range, right_range, &min, &max)) { 1624 if (!Range::Mul(left_range, right_range, &min, &max)) {
1499 return NULL; 1625 *result = Range::Full(RangeBoundary::kRangeBoundaryInt64);
1626 return;
1500 } 1627 }
1501 break; 1628 break;
1502 } 1629 }
1503 case Token::kSHL: { 1630 case Token::kSHL: {
1504 Range::Shl(left_range, right_range, &min, &max); 1631 Range::Shl(left_range, right_range, &min, &max);
1505 break; 1632 break;
1506 } 1633 }
1507 case Token::kSHR: { 1634 case Token::kSHR: {
1508 Range::Shr(left_range, right_range, &min, &max); 1635 Range::Shr(left_range, right_range, &min, &max);
1509 break; 1636 break;
1510 } 1637 }
1511 case Token::kBIT_AND: 1638 case Token::kBIT_AND:
1512 if (!Range::And(left_range, right_range, &min, &max)) { 1639 if (!Range::And(left_range, right_range, &min, &max)) {
1513 return NULL; 1640 *result = Range::Full(RangeBoundary::kRangeBoundaryInt64);
1641 return;
1514 } 1642 }
1515 break; 1643 break;
1516 default: 1644 default:
1517 return NULL; 1645 *result = Range::Full(RangeBoundary::kRangeBoundaryInt64);
1518 break; 1646 return;
1519 } 1647 }
1520 1648
1521 ASSERT(!min.IsUnknown() && !max.IsUnknown()); 1649 ASSERT(!min.IsUnknown() && !max.IsUnknown());
1522 1650
1523 return new Range(min, max); 1651 *result = Range(min, max);
1524 } 1652 }
1525 1653
1526 1654
1527 void Definition::InferRange() { 1655 void Definition::set_range(const Range& range) {
1656 if (range_ == NULL) {
1657 range_ = new Range();
1658 }
1659 *range_ = range;
1660 }
1661
1662
1663 void Definition::InferRange(RangeAnalysis* analysis, Range* range) {
1528 if (Type()->ToCid() == kSmiCid) { 1664 if (Type()->ToCid() == kSmiCid) {
1529 if (range_ == NULL) { 1665 *range = Range::Full(RangeBoundary::kRangeBoundarySmi);
1530 range_ = Range::UnknownSmi();
1531 }
1532 } else if (IsMintDefinition()) { 1666 } else if (IsMintDefinition()) {
1533 if (range_ == NULL) { 1667 *range = Range::Full(RangeBoundary::kRangeBoundaryInt64);
1534 range_ = Range::Unknown();
1535 }
1536 } else { 1668 } else {
1537 // Only Smi and Mint supported. 1669 // Only Smi and Mint supported.
1538 UNREACHABLE(); 1670 UNREACHABLE();
1539 } 1671 }
1540 } 1672 }
1541 1673
1542 1674
1543 void PhiInstr::InferRange() { 1675 static bool DependsOnSymbol(const RangeBoundary& a, Definition* symbol) {
1544 RangeBoundary new_min; 1676 return a.IsSymbol() && (UnwrapConstraint(a.symbol()) == symbol);
1545 RangeBoundary new_max; 1677 }
1546 1678
1547 ASSERT(Type()->ToCid() == kSmiCid);
1548 1679
1549 for (intptr_t i = 0; i < InputCount(); i++) { 1680 // Given the range and definition update the range so that
1550 Range* input_range = InputAt(i)->definition()->range(); 1681 // it covers both original range and defintions range.
1551 if (input_range == NULL) { 1682 //
1552 range_ = Range::UnknownSmi(); 1683 // The following should also hold:
1553 return; 1684 //
1554 } 1685 // [_|_, _|_] U a = a U [_|_, _|_] = a
1555 1686 //
1556 if (new_min.IsUnknown()) { 1687 static void Join(Range* range, Definition* defn, const Range* defn_range) {
1557 new_min = Range::ConstantMin(input_range); 1688 if (Range::IsUnknown(defn_range)) {
1558 } else {
1559 new_min = RangeBoundary::Min(new_min,
1560 Range::ConstantMinSmi(input_range),
1561 RangeBoundary::kRangeBoundarySmi);
1562 }
1563
1564 if (new_max.IsUnknown()) {
1565 new_max = Range::ConstantMax(input_range);
1566 } else {
1567 new_max = RangeBoundary::Max(new_max,
1568 Range::ConstantMaxSmi(input_range),
1569 RangeBoundary::kRangeBoundarySmi);
1570 }
1571 }
1572
1573 ASSERT(new_min.IsUnknown() == new_max.IsUnknown());
1574 if (new_min.IsUnknown()) {
1575 range_ = Range::UnknownSmi();
1576 return; 1689 return;
1577 } 1690 }
1578 1691
1579 range_ = new Range(new_min, new_max); 1692 if (Range::IsUnknown(range)) {
1693 *range = *defn_range;
1694 return;
1695 }
1696
1697 Range other = *defn_range;
1698
1699 // Handle patterns where range already depends on defn as a symbol:
1700 //
1701 // (..., S+o] U range(S) and [S+o, ...) U range(S)
1702 //
1703 // To improve precision of the computed join use [S, S] instead of
1704 // using range(S). It will be canonicalized away by JoinMin/JoinMax
1705 // functions.
1706 Definition* unwrapped = UnwrapConstraint(defn);
1707 if (DependsOnSymbol(range->min(), unwrapped) ||
1708 DependsOnSymbol(range->max(), unwrapped)) {
1709 other = Range(RangeBoundary::FromDefinition(defn, 0),
1710 RangeBoundary::FromDefinition(defn, 0));
1711 }
1712
1713 // First try to compare ranges based on their upper and lower bounds.
1714 const int64_t inf_range = range->min().SmiLowerBound();
1715 const int64_t inf_other = other.min().SmiLowerBound();
1716 const int64_t sup_range = range->max().SmiUpperBound();
1717 const int64_t sup_other = other.max().SmiUpperBound();
1718
1719 if (sup_range <= inf_other) {
1720 // The range is fully below defn's range. Keep the minimum and
1721 // expand the maximum.
1722 range->set_max(other.max());
1723 } else if (sup_other <= inf_range) {
1724 // The range is fully above defn's range. Keep the maximum and
1725 // expand the minimum.
1726 range->set_min(other.min());
1727 } else {
1728 // Can't compare ranges as whole. Join minimum and maximum separately.
1729 *range = Range(RangeBoundary::JoinMin(range->min(), other.min()),
1730 RangeBoundary::JoinMax(range->max(), other.max()));
1731 }
1580 } 1732 }
1581 1733
1582 1734
1583 void ConstantInstr::InferRange() { 1735 // When assigning range to a phi we must take care to avoid self-reference
1736 // cycles when phi's range depends on the phi itself.
1737 // To prevent such cases we impose additional restriction on symbols that
1738 // can be used as boundaries for phi's range: they must dominate
1739 // phi's definition.
1740 static RangeBoundary EnsureAcyclicSymbol(BlockEntryInstr* phi_block,
1741 const RangeBoundary& a,
1742 const RangeBoundary& limit) {
1743 if (!a.IsSymbol() || a.symbol()->GetBlock()->Dominates(phi_block)) {
1744 return a;
1745 }
1746
1747 // Symbol does not dominate phi. Try unwrapping constraint and check again.
1748 Definition* unwrapped = UnwrapConstraint(a.symbol());
1749 if ((unwrapped != a.symbol()) &&
1750 unwrapped->GetBlock()->Dominates(phi_block)) {
1751 return RangeBoundary::FromDefinition(unwrapped, a.offset());
1752 }
1753
1754 return limit;
1755 }
1756
1757
1758 void PhiInstr::InferRange(RangeAnalysis* analysis, Range* range) {
1759 ASSERT(Type()->ToCid() == kSmiCid);
1760 for (intptr_t i = 0; i < InputCount(); i++) {
1761 Value* input = InputAt(i);
1762 Join(range, input->definition(), analysis->GetRange(input));
1763 }
1764
1765 BlockEntryInstr* phi_block = GetBlock();
1766 range->set_min(EnsureAcyclicSymbol(
1767 phi_block, range->min(), RangeBoundary::MinSmi()));
1768 range->set_max(EnsureAcyclicSymbol(
1769 phi_block, range->max(), RangeBoundary::MaxSmi()));
1770 }
1771
1772
1773 void ConstantInstr::InferRange(RangeAnalysis* analysis, Range* range) {
1584 if (value_.IsSmi()) { 1774 if (value_.IsSmi()) {
1585 if (range_ == NULL) { 1775 int64_t value = Smi::Cast(value_).Value();
1586 int64_t value = Smi::Cast(value_).Value(); 1776 *range = Range(RangeBoundary::FromConstant(value),
1587 range_ = new Range(RangeBoundary::FromConstant(value), 1777 RangeBoundary::FromConstant(value));
1588 RangeBoundary::FromConstant(value));
1589 }
1590 } else if (value_.IsMint()) { 1778 } else if (value_.IsMint()) {
1591 if (range_ == NULL) { 1779 int64_t value = Mint::Cast(value_).value();
1592 int64_t value = Mint::Cast(value_).value(); 1780 *range = Range(RangeBoundary::FromConstant(value),
1593 range_ = new Range(RangeBoundary::FromConstant(value), 1781 RangeBoundary::FromConstant(value));
1594 RangeBoundary::FromConstant(value));
1595 }
1596 } else { 1782 } else {
1597 // Only Smi and Mint supported. 1783 // Only Smi and Mint supported.
1598 UNREACHABLE(); 1784 UNREACHABLE();
1599 } 1785 }
1600 } 1786 }
1601 1787
1602 1788
1603 void UnboxIntegerInstr::InferRange() { 1789 void ConstraintInstr::InferRange(RangeAnalysis* analysis, Range* range) {
1604 if (range_ == NULL) {
1605 Definition* unboxed = value()->definition();
1606 ASSERT(unboxed != NULL);
1607 Range* range = unboxed->range();
1608 if (range == NULL) {
1609 range_ = Range::Unknown();
1610 return;
1611 }
1612 range_ = new Range(range->min(), range->max());
1613 }
1614 }
1615
1616
1617 void ConstraintInstr::InferRange() {
1618 Range* value_range = value()->definition()->range();
1619
1620 // Only constraining smi values. 1790 // Only constraining smi values.
1621 ASSERT(value()->IsSmiValue()); 1791 ASSERT(value()->IsSmiValue());
1622 1792
1623 RangeBoundary min; 1793 const Range* value_range = analysis->GetRange(value());
1624 RangeBoundary max; 1794 if (Range::IsUnknown(value_range)) {
1625 1795 return;
1626 { 1796 }
1627 RangeBoundary value_min = (value_range == NULL) ? 1797
1628 RangeBoundary() : value_range->min(); 1798 // TODO(vegorov) check if precision of the analysis can be improved by
1629 RangeBoundary constraint_min = constraint()->min(); 1799 // recognizing intersections of the form:
1630 min = RangeBoundary::Max(value_min, constraint_min, 1800 //
1631 RangeBoundary::kRangeBoundarySmi); 1801 // (..., S+x] ^ [S+x, ...) = [S+x, S+x]
1632 } 1802 //
1633 1803 Range result = value_range->Intersect(constraint());
1634 ASSERT(!min.IsUnknown()); 1804
1635 1805 if (result.IsUnsatisfiable()) {
1636 { 1806 return;
1637 RangeBoundary value_max = (value_range == NULL) ? 1807 }
1638 RangeBoundary() : value_range->max(); 1808
1639 RangeBoundary constraint_max = constraint()->max(); 1809 *range = result;
1640 max = RangeBoundary::Min(value_max, constraint_max, 1810 }
1641 RangeBoundary::kRangeBoundarySmi); 1811
1642 } 1812
1643 1813 void LoadFieldInstr::InferRange(RangeAnalysis* analysis, Range* range) {
1644 ASSERT(!max.IsUnknown()); 1814 switch (recognized_kind()) {
1645 1815 case MethodRecognizer::kObjectArrayLength:
1646 range_ = new Range(min, max); 1816 case MethodRecognizer::kImmutableArrayLength:
1647 1817 *range = Range(RangeBoundary::FromConstant(0),
1648 // Mark branches that generate unsatisfiable constraints as constant. 1818 RangeBoundary::FromConstant(Array::kMaxElements));
1649 if (target() != NULL && range_->IsUnsatisfiable()) { 1819 break;
1650 BranchInstr* branch = 1820
1651 target()->PredecessorAt(0)->last_instruction()->AsBranch(); 1821 case MethodRecognizer::kTypedDataLength:
1652 if (target() == branch->true_successor()) { 1822 *range = Range(RangeBoundary::FromConstant(0), RangeBoundary::MaxSmi());
1653 // True unreachable. 1823 break;
1654 if (FLAG_trace_constant_propagation) { 1824
1655 OS::Print("Range analysis: True unreachable (B%" Pd ")\n", 1825 case MethodRecognizer::kStringBaseLength:
1656 branch->true_successor()->block_id()); 1826 *range = Range(RangeBoundary::FromConstant(0),
1657 } 1827 RangeBoundary::FromConstant(String::kMaxElements));
1658 branch->set_constant_target(branch->false_successor()); 1828 break;
1659 } else { 1829
1660 ASSERT(target() == branch->false_successor()); 1830 default:
1661 // False unreachable. 1831 Definition::InferRange(analysis, range);
1662 if (FLAG_trace_constant_propagation) { 1832 }
1663 OS::Print("Range analysis: False unreachable (B%" Pd ")\n", 1833 }
1664 branch->false_successor()->block_id()); 1834
1665 } 1835
1666 branch->set_constant_target(branch->true_successor()); 1836
1667 } 1837 void LoadIndexedInstr::InferRange(RangeAnalysis* analysis, Range* range) {
1668 }
1669 }
1670
1671
1672 void LoadFieldInstr::InferRange() {
1673 if ((range_ == NULL) &&
1674 ((recognized_kind() == MethodRecognizer::kObjectArrayLength) ||
1675 (recognized_kind() == MethodRecognizer::kImmutableArrayLength))) {
1676 range_ = new Range(RangeBoundary::FromConstant(0),
1677 RangeBoundary::FromConstant(Array::kMaxElements));
1678 return;
1679 }
1680 if ((range_ == NULL) &&
1681 (recognized_kind() == MethodRecognizer::kTypedDataLength)) {
1682 range_ = new Range(RangeBoundary::FromConstant(0), RangeBoundary::MaxSmi());
1683 return;
1684 }
1685 if ((range_ == NULL) &&
1686 (recognized_kind() == MethodRecognizer::kStringBaseLength)) {
1687 range_ = new Range(RangeBoundary::FromConstant(0),
1688 RangeBoundary::FromConstant(String::kMaxElements));
1689 return;
1690 }
1691 Definition::InferRange();
1692 }
1693
1694
1695
1696 void LoadIndexedInstr::InferRange() {
1697 switch (class_id()) { 1838 switch (class_id()) {
1698 case kTypedDataInt8ArrayCid: 1839 case kTypedDataInt8ArrayCid:
1699 range_ = new Range(RangeBoundary::FromConstant(-128), 1840 *range = Range(RangeBoundary::FromConstant(-128),
1700 RangeBoundary::FromConstant(127)); 1841 RangeBoundary::FromConstant(127));
1701 break; 1842 break;
1702 case kTypedDataUint8ArrayCid: 1843 case kTypedDataUint8ArrayCid:
1703 case kTypedDataUint8ClampedArrayCid: 1844 case kTypedDataUint8ClampedArrayCid:
1704 case kExternalTypedDataUint8ArrayCid: 1845 case kExternalTypedDataUint8ArrayCid:
1705 case kExternalTypedDataUint8ClampedArrayCid: 1846 case kExternalTypedDataUint8ClampedArrayCid:
1706 range_ = new Range(RangeBoundary::FromConstant(0), 1847 *range = Range(RangeBoundary::FromConstant(0),
1707 RangeBoundary::FromConstant(255)); 1848 RangeBoundary::FromConstant(255));
1708 break; 1849 break;
1709 case kTypedDataInt16ArrayCid: 1850 case kTypedDataInt16ArrayCid:
1710 range_ = new Range(RangeBoundary::FromConstant(-32768), 1851 *range = Range(RangeBoundary::FromConstant(-32768),
1711 RangeBoundary::FromConstant(32767)); 1852 RangeBoundary::FromConstant(32767));
1712 break; 1853 break;
1713 case kTypedDataUint16ArrayCid: 1854 case kTypedDataUint16ArrayCid:
1714 range_ = new Range(RangeBoundary::FromConstant(0), 1855 *range = Range(RangeBoundary::FromConstant(0),
1715 RangeBoundary::FromConstant(65535)); 1856 RangeBoundary::FromConstant(65535));
1716 break; 1857 break;
1717 case kTypedDataInt32ArrayCid: 1858 case kTypedDataInt32ArrayCid:
1718 if (Typed32BitIsSmi()) { 1859 if (Typed32BitIsSmi()) {
1719 range_ = Range::UnknownSmi(); 1860 *range = Range::Full(RangeBoundary::kRangeBoundarySmi);
1720 } else { 1861 } else {
1721 range_ = new Range(RangeBoundary::FromConstant(kMinInt32), 1862 *range = Range(RangeBoundary::FromConstant(kMinInt32),
1722 RangeBoundary::FromConstant(kMaxInt32)); 1863 RangeBoundary::FromConstant(kMaxInt32));
1723 } 1864 }
1724 break; 1865 break;
1725 case kTypedDataUint32ArrayCid: 1866 case kTypedDataUint32ArrayCid:
1726 if (Typed32BitIsSmi()) { 1867 if (Typed32BitIsSmi()) {
1727 range_ = Range::UnknownSmi(); 1868 *range = Range::Full(RangeBoundary::kRangeBoundarySmi);
1728 } else { 1869 } else {
1729 range_ = new Range(RangeBoundary::FromConstant(0), 1870 *range = Range(RangeBoundary::FromConstant(0),
1730 RangeBoundary::FromConstant(kMaxUint32)); 1871 RangeBoundary::FromConstant(kMaxUint32));
1731 } 1872 }
1732 break; 1873 break;
1733 case kOneByteStringCid: 1874 case kOneByteStringCid:
1734 range_ = new Range(RangeBoundary::FromConstant(0), 1875 *range = Range(RangeBoundary::FromConstant(0),
1735 RangeBoundary::FromConstant(0xFF)); 1876 RangeBoundary::FromConstant(0xFF));
1736 break; 1877 break;
1737 case kTwoByteStringCid: 1878 case kTwoByteStringCid:
1738 range_ = new Range(RangeBoundary::FromConstant(0), 1879 *range = Range(RangeBoundary::FromConstant(0),
1739 RangeBoundary::FromConstant(0xFFFF)); 1880 RangeBoundary::FromConstant(0xFFFF));
1740 break; 1881 break;
1741 default: 1882 default:
1742 Definition::InferRange(); 1883 Definition::InferRange(analysis, range);
1743 break; 1884 break;
1744 } 1885 }
1745 } 1886 }
1746 1887
1747 1888
1748 void IfThenElseInstr::InferRange() { 1889 void IfThenElseInstr::InferRange(RangeAnalysis* analysis, Range* range) {
1749 const intptr_t min = Utils::Minimum(if_true_, if_false_); 1890 const intptr_t min = Utils::Minimum(if_true_, if_false_);
1750 const intptr_t max = Utils::Maximum(if_true_, if_false_); 1891 const intptr_t max = Utils::Maximum(if_true_, if_false_);
1751 range_ = new Range(RangeBoundary::FromConstant(min), 1892 *range = Range(RangeBoundary::FromConstant(min),
1752 RangeBoundary::FromConstant(max)); 1893 RangeBoundary::FromConstant(max));
1753 } 1894 }
1754 1895
1755 1896
1756 void BinarySmiOpInstr::InferRange() { 1897 void BinarySmiOpInstr::InferRange(RangeAnalysis* analysis, Range* range) {
1757 // TODO(vegorov): canonicalize BinarySmiOp to always have constant on the 1898 // TODO(vegorov): canonicalize BinarySmiOp to always have constant on the
1758 // right and a non-constant on the left. 1899 // right and a non-constant on the left.
1759 Definition* left_defn = left()->definition(); 1900 Definition* left_defn = left()->definition();
1760 1901
1761 Range* left_range = left_defn->range(); 1902 const Range* left_range = analysis->GetRange(left());
1762 Range* right_range = right()->definition()->range(); 1903 const Range* right_range = analysis->GetRange(right());
1763 1904
1764 if ((left_range == NULL) || (right_range == NULL)) { 1905 if (Range::IsUnknown(left_range) || Range::IsUnknown(right_range)) {
1765 range_ = Range::UnknownSmi(); 1906 return;
1766 return; 1907 }
1767 } 1908
1768 1909 Range::BinaryOp(op_kind(),
1769 Range* possible_range = Range::BinaryOp(op_kind(), 1910 left_range,
1770 left_range, 1911 right_range,
1771 right_range, 1912 left_defn,
1772 left_defn); 1913 range);
1773 1914 ASSERT(!Range::IsUnknown(range));
1774 if ((range_ == NULL) && (possible_range == NULL)) { 1915
1775 // Initialize.
1776 range_ = Range::UnknownSmi();
1777 return;
1778 }
1779
1780 if (possible_range == NULL) {
1781 // Nothing new.
1782 return;
1783 }
1784
1785 range_ = possible_range;
1786
1787 ASSERT(!range_->min().IsUnknown() && !range_->max().IsUnknown());
1788 // Calculate overflowed status before clamping. 1916 // Calculate overflowed status before clamping.
1789 const bool overflowed = range_->min().LowerBound().OverflowedSmi() || 1917 const bool overflowed = range->min().LowerBound().OverflowedSmi() ||
1790 range_->max().UpperBound().OverflowedSmi(); 1918 range->max().UpperBound().OverflowedSmi();
1791 set_overflow(overflowed); 1919 set_overflow(overflowed);
1792 1920
1793 // Clamp value to be within smi range. 1921 // Clamp value to be within smi range.
1794 range_->Clamp(RangeBoundary::kRangeBoundarySmi); 1922 range->Clamp(RangeBoundary::kRangeBoundarySmi);
1795 } 1923 }
1796 1924
1797 1925
1798 void BinaryMintOpInstr::InferRange() { 1926 void BinaryMintOpInstr::InferRange(RangeAnalysis* analysis, Range* range) {
1799 // TODO(vegorov): canonicalize BinaryMintOpInstr to always have constant on 1927 // TODO(vegorov): canonicalize BinaryMintOpInstr to always have constant on
1800 // the right and a non-constant on the left. 1928 // the right and a non-constant on the left.
1801 Definition* left_defn = left()->definition(); 1929 Definition* left_defn = left()->definition();
1802 1930
1803 Range* left_range = left_defn->range(); 1931 const Range* left_range = analysis->GetRange(left());
1804 Range* right_range = right()->definition()->range(); 1932 const Range* right_range = analysis->GetRange(right());
1805 1933
1806 if ((left_range == NULL) || (right_range == NULL)) { 1934 if (Range::IsUnknown(left_range) || Range::IsUnknown(right_range)) {
1807 range_ = Range::Unknown(); 1935 return;
1808 return; 1936 }
1809 } 1937
1810 1938 Range::BinaryOp(op_kind(),
1811 Range* possible_range = Range::BinaryOp(op_kind(), 1939 left_range,
1812 left_range, 1940 right_range,
1813 right_range, 1941 left_defn,
1814 left_defn); 1942 range);
1815 1943 ASSERT(!Range::IsUnknown(range));
1816 if ((range_ == NULL) && (possible_range == NULL)) {
1817 // Initialize.
1818 range_ = Range::Unknown();
1819 return;
1820 }
1821
1822 if (possible_range == NULL) {
1823 // Nothing new.
1824 return;
1825 }
1826
1827 range_ = possible_range;
1828
1829 ASSERT(!range_->min().IsUnknown() && !range_->max().IsUnknown());
1830 1944
1831 // Calculate overflowed status before clamping. 1945 // Calculate overflowed status before clamping.
1832 const bool overflowed = range_->min().LowerBound().OverflowedMint() || 1946 const bool overflowed = range->min().LowerBound().OverflowedMint() ||
1833 range_->max().UpperBound().OverflowedMint(); 1947 range->max().UpperBound().OverflowedMint();
1834 set_can_overflow(overflowed); 1948 set_can_overflow(overflowed);
1835 1949
1836 // Clamp value to be within mint range. 1950 // Clamp value to be within mint range.
1837 range_->Clamp(RangeBoundary::kRangeBoundaryInt64); 1951 range->Clamp(RangeBoundary::kRangeBoundaryInt64);
1838 } 1952 }
1839 1953
1840 1954
1841 void ShiftMintOpInstr::InferRange() { 1955 void ShiftMintOpInstr::InferRange(RangeAnalysis* analysis, Range* range) {
1842 Definition* left_defn = left()->definition(); 1956 Definition* left_defn = left()->definition();
1843 1957
1844 Range* left_range = left_defn->range(); 1958 const Range* left_range = analysis->GetRange(left());
1845 Range* right_range = right()->definition()->range(); 1959 const Range* right_range = analysis->GetRange(right());
1846 1960
1847 if ((left_range == NULL) || (right_range == NULL)) { 1961 if (Range::IsUnknown(left_range) || Range::IsUnknown(right_range)) {
1848 range_ = Range::Unknown(); 1962 return;
1849 return; 1963 }
1850 } 1964
1851 1965 Range::BinaryOp(op_kind(),
1852 Range* possible_range = Range::BinaryOp(op_kind(), 1966 left_range,
1853 left_range, 1967 right_range,
1854 right_range, 1968 left_defn,
1855 left_defn); 1969 range);
1856 1970 ASSERT(!Range::IsUnknown(range));
1857 if ((range_ == NULL) && (possible_range == NULL)) {
1858 // Initialize.
1859 range_ = Range::Unknown();
1860 return;
1861 }
1862
1863 if (possible_range == NULL) {
1864 // Nothing new.
1865 return;
1866 }
1867
1868 range_ = possible_range;
1869
1870 ASSERT(!range_->min().IsUnknown() && !range_->max().IsUnknown());
1871 1971
1872 // Calculate overflowed status before clamping. 1972 // Calculate overflowed status before clamping.
1873 const bool overflowed = range_->min().LowerBound().OverflowedMint() || 1973 const bool overflowed = range->min().LowerBound().OverflowedMint() ||
1874 range_->max().UpperBound().OverflowedMint(); 1974 range->max().UpperBound().OverflowedMint();
1875 set_can_overflow(overflowed); 1975 set_can_overflow(overflowed);
1876 1976
1877 // Clamp value to be within mint range. 1977 // Clamp value to be within mint range.
1878 range_->Clamp(RangeBoundary::kRangeBoundaryInt64); 1978 range->Clamp(RangeBoundary::kRangeBoundaryInt64);
1879 } 1979 }
1880 1980
1881 1981
1882 void BoxIntegerInstr::InferRange() { 1982 void BoxIntegerInstr::InferRange(RangeAnalysis* analysis, Range* range) {
1883 Range* input_range = value()->definition()->range(); 1983 const Range* input_range = analysis->GetRange(value());
1884 if (input_range != NULL) { 1984 if (input_range != NULL) {
1885 bool is_smi = !input_range->min().LowerBound().OverflowedSmi() && 1985 bool is_smi = !input_range->min().LowerBound().OverflowedSmi() &&
1886 !input_range->max().UpperBound().OverflowedSmi(); 1986 !input_range->max().UpperBound().OverflowedSmi();
1887 set_is_smi(is_smi); 1987 set_is_smi(is_smi);
1888 // The output range is the same as the input range. 1988 // The output range is the same as the input range.
1889 range_ = input_range; 1989 *range = *input_range;
1890 } 1990 }
1891 } 1991 }
1892 1992
1993
1994 void UnboxIntegerInstr::InferRange(RangeAnalysis* analysis, Range* range) {
1995 const Range* value_range = analysis->GetRange(value());
1996 if (value_range != NULL) {
1997 *range = *value_range;
1998 } else if (!value()->definition()->IsMintDefinition() &&
1999 (value()->Type()->ToCid() != kSmiCid)) {
2000 *range = Range::Full(RangeBoundary::kRangeBoundaryInt64);
2001 }
2002 }
2003
1893 2004
1894 bool CheckArrayBoundInstr::IsRedundant(const RangeBoundary& length) { 2005 bool CheckArrayBoundInstr::IsRedundant(const RangeBoundary& length) {
1895 Range* index_range = index()->definition()->range(); 2006 Range* index_range = index()->definition()->range();
1896 2007
1897 // Range of the index is unknown can't decide if the check is redundant. 2008 // Range of the index is unknown can't decide if the check is redundant.
1898 if (index_range == NULL) { 2009 if (index_range == NULL) {
1899 return false; 2010 return false;
1900 } 2011 }
1901 2012
1902 // Range of the index is not positive. Check can't be redundant. 2013 // Range of the index is not positive. Check can't be redundant.
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
1937 } 2048 }
1938 } while (CanonicalizeMaxBoundary(&max) || 2049 } while (CanonicalizeMaxBoundary(&max) ||
1939 CanonicalizeMinBoundary(&canonical_length)); 2050 CanonicalizeMinBoundary(&canonical_length));
1940 2051
1941 // Failed to prove that maximum is bounded with array length. 2052 // Failed to prove that maximum is bounded with array length.
1942 return false; 2053 return false;
1943 } 2054 }
1944 2055
1945 2056
1946 } // namespace dart 2057 } // namespace dart
OLDNEW
« no previous file with comments | « runtime/vm/flow_graph_range_analysis.h ('k') | runtime/vm/flow_graph_range_analysis_test.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698