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

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

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_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
(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 #include "vm/flow_graph_range_analysis.h"
6
7 #include "vm/bit_vector.h"
8 #include "vm/il_printer.h"
9
10 namespace dart {
11
12 DEFINE_FLAG(bool, array_bounds_check_elimination, true,
13 "Eliminate redundant bounds checks.");
14 DEFINE_FLAG(bool, trace_range_analysis, false, "Trace range analysis progress");
15 DEFINE_FLAG(bool, trace_integer_ir_selection, false,
16 "Print integer IR selection optimization pass.");
17 DECLARE_FLAG(bool, trace_constant_propagation);
18
19 // Quick access to the locally defined isolate() method.
20 #define I (isolate())
21
22 void RangeAnalysis::Analyze() {
23 CollectValues();
24 InsertConstraints();
25 InferRanges();
26 IntegerInstructionSelector iis(flow_graph_);
27 iis.Select();
28 RemoveConstraints();
29 }
30
31
32 void RangeAnalysis::CollectValues() {
33 const GrowableArray<Definition*>& initial =
34 *flow_graph_->graph_entry()->initial_definitions();
35 for (intptr_t i = 0; i < initial.length(); ++i) {
36 Definition* current = initial[i];
37 if (current->Type()->ToCid() == kSmiCid) {
38 values_.Add(current);
39 } else if (current->IsMintDefinition()) {
40 values_.Add(current);
41 }
42 }
43
44 for (BlockIterator block_it = flow_graph_->reverse_postorder_iterator();
45 !block_it.Done();
46 block_it.Advance()) {
47 BlockEntryInstr* block = block_it.Current();
48
49
50 if (block->IsGraphEntry() || block->IsCatchBlockEntry()) {
51 const GrowableArray<Definition*>& initial = block->IsGraphEntry()
52 ? *block->AsGraphEntry()->initial_definitions()
53 : *block->AsCatchBlockEntry()->initial_definitions();
54 for (intptr_t i = 0; i < initial.length(); ++i) {
55 Definition* current = initial[i];
56 if (current->Type()->ToCid() == kSmiCid) {
57 values_.Add(current);
58 } else if (current->IsMintDefinition()) {
59 values_.Add(current);
60 }
61 }
62 }
63
64 JoinEntryInstr* join = block->AsJoinEntry();
65 if (join != NULL) {
66 for (PhiIterator phi_it(join); !phi_it.Done(); phi_it.Advance()) {
67 PhiInstr* current = phi_it.Current();
68 if (current->Type()->ToCid() == kSmiCid) {
69 values_.Add(current);
70 }
71 }
72 }
73
74 for (ForwardInstructionIterator instr_it(block);
75 !instr_it.Done();
76 instr_it.Advance()) {
77 Instruction* current = instr_it.Current();
78 Definition* defn = current->AsDefinition();
79 if (defn != NULL) {
80 if ((defn->Type()->ToCid() == kSmiCid) &&
81 (defn->ssa_temp_index() != -1)) {
82 values_.Add(defn);
83 } else if ((defn->IsMintDefinition()) &&
84 (defn->ssa_temp_index() != -1)) {
85 values_.Add(defn);
86 }
87 } else if (current->IsCheckSmi()) {
88 smi_checks_.Add(current->AsCheckSmi());
89 }
90 }
91 }
92 }
93
94
95 // Returns true if use is dominated by the given instruction.
96 // Note: uses that occur at instruction itself are not dominated by it.
97 static bool IsDominatedUse(Instruction* dom, Value* use) {
98 BlockEntryInstr* dom_block = dom->GetBlock();
99
100 Instruction* instr = use->instruction();
101
102 PhiInstr* phi = instr->AsPhi();
103 if (phi != NULL) {
104 return dom_block->Dominates(phi->block()->PredecessorAt(use->use_index()));
105 }
106
107 BlockEntryInstr* use_block = instr->GetBlock();
108 if (use_block == dom_block) {
109 // Fast path for the case of block entry.
110 if (dom_block == dom) return true;
111
112 for (Instruction* curr = dom->next(); curr != NULL; curr = curr->next()) {
113 if (curr == instr) return true;
114 }
115
116 return false;
117 }
118
119 return dom_block->Dominates(use_block);
120 }
121
122
123 void RangeAnalysis::RenameDominatedUses(Definition* def,
124 Instruction* dom,
125 Definition* other) {
126 for (Value::Iterator it(def->input_use_list());
127 !it.Done();
128 it.Advance()) {
129 Value* use = it.Current();
130
131 // Skip dead phis.
132 PhiInstr* phi = use->instruction()->AsPhi();
133 ASSERT((phi == NULL) || phi->is_alive());
134 if (IsDominatedUse(dom, use)) {
135 use->BindTo(other);
136 }
137 }
138 }
139
140
141 // For a comparison operation return an operation for the equivalent flipped
142 // comparison: a (op) b === b (op') a.
143 static Token::Kind FlipComparison(Token::Kind op) {
144 switch (op) {
145 case Token::kEQ: return Token::kEQ;
146 case Token::kNE: return Token::kNE;
147 case Token::kLT: return Token::kGT;
148 case Token::kGT: return Token::kLT;
149 case Token::kLTE: return Token::kGTE;
150 case Token::kGTE: return Token::kLTE;
151 default:
152 UNREACHABLE();
153 return Token::kILLEGAL;
154 }
155 }
156
157
158 // Given a boundary (right operand) and a comparison operation return
159 // a symbolic range constraint for the left operand of the comparison assuming
160 // that it evaluated to true.
161 // For example for the comparison a < b symbol a is constrained with range
162 // [Smi::kMinValue, b - 1].
163 Range* RangeAnalysis::ConstraintRange(Token::Kind op, Definition* boundary) {
164 switch (op) {
165 case Token::kEQ:
166 return new(I) Range(RangeBoundary::FromDefinition(boundary),
167 RangeBoundary::FromDefinition(boundary));
168 case Token::kNE:
169 return Range::Unknown();
170 case Token::kLT:
171 return new(I) Range(RangeBoundary::MinSmi(),
172 RangeBoundary::FromDefinition(boundary, -1));
173 case Token::kGT:
174 return new(I) Range(RangeBoundary::FromDefinition(boundary, 1),
175 RangeBoundary::MaxSmi());
176 case Token::kLTE:
177 return new(I) Range(RangeBoundary::MinSmi(),
178 RangeBoundary::FromDefinition(boundary));
179 case Token::kGTE:
180 return new(I) Range(RangeBoundary::FromDefinition(boundary),
181 RangeBoundary::MaxSmi());
182 default:
183 UNREACHABLE();
184 return Range::Unknown();
185 }
186 }
187
188
189 ConstraintInstr* RangeAnalysis::InsertConstraintFor(Definition* defn,
190 Range* constraint_range,
191 Instruction* after) {
192 // No need to constrain constants.
193 if (defn->IsConstant()) return NULL;
194
195 ConstraintInstr* constraint = new(I) ConstraintInstr(
196 new(I) Value(defn), constraint_range);
197 flow_graph_->InsertAfter(after, constraint, NULL, FlowGraph::kValue);
198 RenameDominatedUses(defn, constraint, constraint);
199 constraints_.Add(constraint);
200 return constraint;
201 }
202
203
204 void RangeAnalysis::ConstrainValueAfterBranch(Definition* defn, Value* use) {
205 BranchInstr* branch = use->instruction()->AsBranch();
206 RelationalOpInstr* rel_op = branch->comparison()->AsRelationalOp();
207 if ((rel_op != NULL) && (rel_op->operation_cid() == kSmiCid)) {
208 // Found comparison of two smis. Constrain defn at true and false
209 // successors using the other operand as a boundary.
210 Definition* boundary;
211 Token::Kind op_kind;
212 if (use->use_index() == 0) { // Left operand.
213 boundary = rel_op->InputAt(1)->definition();
214 op_kind = rel_op->kind();
215 } else {
216 ASSERT(use->use_index() == 1); // Right operand.
217 boundary = rel_op->InputAt(0)->definition();
218 // InsertConstraintFor assumes that defn is left operand of a
219 // comparison if it is right operand flip the comparison.
220 op_kind = FlipComparison(rel_op->kind());
221 }
222
223 // Constrain definition at the true successor.
224 ConstraintInstr* true_constraint =
225 InsertConstraintFor(defn,
226 ConstraintRange(op_kind, boundary),
227 branch->true_successor());
228 // Mark true_constraint an artificial use of boundary. This ensures
229 // that constraint's range is recalculated if boundary's range changes.
230 if (true_constraint != NULL) {
231 true_constraint->AddDependency(boundary);
232 true_constraint->set_target(branch->true_successor());
233 }
234
235 // Constrain definition with a negated condition at the false successor.
236 ConstraintInstr* false_constraint =
237 InsertConstraintFor(
238 defn,
239 ConstraintRange(Token::NegateComparison(op_kind), boundary),
240 branch->false_successor());
241 // Mark false_constraint an artificial use of boundary. This ensures
242 // that constraint's range is recalculated if boundary's range changes.
243 if (false_constraint != NULL) {
244 false_constraint->AddDependency(boundary);
245 false_constraint->set_target(branch->false_successor());
246 }
247 }
248 }
249
250
251 void RangeAnalysis::InsertConstraintsFor(Definition* defn) {
252 for (Value* use = defn->input_use_list();
253 use != NULL;
254 use = use->next_use()) {
255 if (use->instruction()->IsBranch()) {
256 ConstrainValueAfterBranch(defn, use);
257 } else if (use->instruction()->IsCheckArrayBound()) {
258 ConstrainValueAfterCheckArrayBound(
259 defn,
260 use->instruction()->AsCheckArrayBound(),
261 use->use_index());
262 }
263 }
264 }
265
266
267 void RangeAnalysis::ConstrainValueAfterCheckArrayBound(
268 Definition* defn, CheckArrayBoundInstr* check, intptr_t use_index) {
269 Range* constraint_range = NULL;
270 if (use_index == CheckArrayBoundInstr::kIndexPos) {
271 Definition* length = check->length()->definition();
272 constraint_range = new(I) Range(
273 RangeBoundary::FromConstant(0),
274 RangeBoundary::FromDefinition(length, -1));
275 } else {
276 ASSERT(use_index == CheckArrayBoundInstr::kLengthPos);
277 Definition* index = check->index()->definition();
278 constraint_range = new(I) Range(
279 RangeBoundary::FromDefinition(index, 1),
280 RangeBoundary::MaxSmi());
281 }
282 InsertConstraintFor(defn, constraint_range, check);
283 }
284
285
286 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++) {
304 InsertConstraintsFor(values_[i]);
305 }
306
307 for (intptr_t i = 0; i < constraints_.length(); i++) {
308 InsertConstraintsFor(constraints_[i]);
309 }
310 }
311
312
313 void RangeAnalysis::ResetWorklist() {
314 if (marked_defns_ == NULL) {
315 marked_defns_ = new(I) BitVector(flow_graph_->current_ssa_temp_index());
316 } else {
317 marked_defns_->Clear();
318 }
319 worklist_.Clear();
320 }
321
322
323 void RangeAnalysis::MarkDefinition(Definition* defn) {
324 // Unwrap constrained value.
325 while (defn->IsConstraint()) {
326 defn = defn->AsConstraint()->value()->definition();
327 }
328
329 if (!marked_defns_->Contains(defn->ssa_temp_index())) {
330 worklist_.Add(defn);
331 marked_defns_->Add(defn->ssa_temp_index());
332 }
333 }
334
335
336 RangeAnalysis::Direction RangeAnalysis::ToDirection(Value* val) {
337 if (val->BindsToConstant()) {
338 return (Smi::Cast(val->BoundConstant()).Value() >= 0) ? kPositive
339 : kNegative;
340 } else if (val->definition()->range() != NULL) {
341 Range* range = val->definition()->range();
342 if (Range::ConstantMin(range).ConstantValue() >= 0) {
343 return kPositive;
344 } else if (Range::ConstantMax(range).ConstantValue() <= 0) {
345 return kNegative;
346 }
347 }
348 return kUnknown;
349 }
350
351
352 Range* RangeAnalysis::InferInductionVariableRange(JoinEntryInstr* loop_header,
353 PhiInstr* var) {
354 BitVector* loop_info = loop_header->loop_info();
355
356 Definition* initial_value = NULL;
357 Direction direction = kUnknown;
358
359 ResetWorklist();
360 MarkDefinition(var);
361 while (!worklist_.is_empty()) {
362 Definition* defn = worklist_.RemoveLast();
363
364 if (defn->IsPhi()) {
365 PhiInstr* phi = defn->AsPhi();
366 for (intptr_t i = 0; i < phi->InputCount(); i++) {
367 Definition* defn = phi->InputAt(i)->definition();
368
369 if (!loop_info->Contains(defn->GetBlock()->preorder_number())) {
370 // The value is coming from outside of the loop.
371 if (initial_value == NULL) {
372 initial_value = defn;
373 continue;
374 } else if (initial_value == defn) {
375 continue;
376 } else {
377 return NULL;
378 }
379 }
380
381 MarkDefinition(defn);
382 }
383 } else if (defn->IsBinarySmiOp()) {
384 BinarySmiOpInstr* binary_op = defn->AsBinarySmiOp();
385
386 switch (binary_op->op_kind()) {
387 case Token::kADD: {
388 const Direction growth_right =
389 ToDirection(binary_op->right());
390 if (growth_right != kUnknown) {
391 UpdateDirection(&direction, growth_right);
392 MarkDefinition(binary_op->left()->definition());
393 break;
394 }
395
396 const Direction growth_left =
397 ToDirection(binary_op->left());
398 if (growth_left != kUnknown) {
399 UpdateDirection(&direction, growth_left);
400 MarkDefinition(binary_op->right()->definition());
401 break;
402 }
403
404 return NULL;
405 }
406
407 case Token::kSUB: {
408 const Direction growth_right =
409 ToDirection(binary_op->right());
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 }
494
495
496 void RangeAnalysis::InferRanges() {
497 if (FLAG_trace_range_analysis) {
498 OS::Print("---- before range analysis -------\n");
499 FlowGraphPrinter printer(*flow_graph_);
500 printer.PrintBlocks();
501 }
502 // Initialize bitvector for quick filtering of int values.
503 definitions_ =
504 new(I) BitVector(flow_graph_->current_ssa_temp_index());
505 for (intptr_t i = 0; i < values_.length(); i++) {
506 definitions_->Add(values_[i]->ssa_temp_index());
507 }
508 for (intptr_t i = 0; i < constraints_.length(); i++) {
509 definitions_->Add(constraints_[i]->ssa_temp_index());
510 }
511
512 // Infer initial values of ranges.
513 const GrowableArray<Definition*>& initial =
514 *flow_graph_->graph_entry()->initial_definitions();
515 for (intptr_t i = 0; i < initial.length(); ++i) {
516 Definition* definition = initial[i];
517 if (definitions_->Contains(definition->ssa_temp_index())) {
518 definition->InferRange();
519 }
520 }
521 InferRangesRecursive(flow_graph_->graph_entry());
522
523 if (FLAG_trace_range_analysis) {
524 OS::Print("---- after range analysis -------\n");
525 FlowGraphPrinter printer(*flow_graph_);
526 printer.PrintBlocks();
527 }
528 }
529
530
531 void RangeAnalysis::RemoveConstraints() {
532 for (intptr_t i = 0; i < constraints_.length(); i++) {
533 Definition* def = constraints_[i]->value()->definition();
534 // Some constraints might be constraining constraints. Unwind the chain of
535 // constraints until we reach the actual definition.
536 while (def->IsConstraint()) {
537 def = def->AsConstraint()->value()->definition();
538 }
539 constraints_[i]->ReplaceUsesWith(def);
540 constraints_[i]->RemoveFromGraph();
541 }
542 }
543
544
545 IntegerInstructionSelector::IntegerInstructionSelector(FlowGraph* flow_graph)
546 : flow_graph_(flow_graph),
547 isolate_(NULL) {
548 ASSERT(flow_graph_ != NULL);
549 isolate_ = flow_graph_->isolate();
550 ASSERT(isolate_ != NULL);
551 selected_uint32_defs_ =
552 new(I) BitVector(flow_graph_->current_ssa_temp_index());
553 }
554
555
556 void IntegerInstructionSelector::Select() {
557 if (FLAG_trace_integer_ir_selection) {
558 OS::Print("---- starting integer ir selection -------\n");
559 }
560 FindPotentialUint32Definitions();
561 FindUint32NarrowingDefinitions();
562 Propagate();
563 ReplaceInstructions();
564 if (FLAG_trace_integer_ir_selection) {
565 OS::Print("---- after integer ir selection -------\n");
566 FlowGraphPrinter printer(*flow_graph_);
567 printer.PrintBlocks();
568 }
569 }
570
571
572 bool IntegerInstructionSelector::IsPotentialUint32Definition(Definition* def) {
573 // TODO(johnmccutchan): Consider Smi operations, to avoid unnecessary tagging
574 // & untagged of intermediate results.
575 // TODO(johnmccutchan): Consider phis.
576 return def->IsBoxInteger() || // BoxMint.
577 def->IsUnboxInteger() || // UnboxMint.
578 def->IsBinaryMintOp() ||
579 def->IsShiftMintOp() ||
580 def->IsUnaryMintOp();
581 }
582
583
584 void IntegerInstructionSelector::FindPotentialUint32Definitions() {
585 if (FLAG_trace_integer_ir_selection) {
586 OS::Print("++++ Finding potential Uint32 definitions:\n");
587 }
588
589 for (BlockIterator block_it = flow_graph_->reverse_postorder_iterator();
590 !block_it.Done();
591 block_it.Advance()) {
592 BlockEntryInstr* block = block_it.Current();
593
594 for (ForwardInstructionIterator instr_it(block);
595 !instr_it.Done();
596 instr_it.Advance()) {
597 Instruction* current = instr_it.Current();
598 Definition* defn = current->AsDefinition();
599 if ((defn != NULL) && (defn->ssa_temp_index() != -1)) {
600 if (IsPotentialUint32Definition(defn)) {
601 if (FLAG_trace_integer_ir_selection) {
602 OS::Print("Adding %s\n", current->ToCString());
603 }
604 potential_uint32_defs_.Add(defn);
605 }
606 }
607 }
608 }
609 }
610
611
612 // BinaryMintOp masks and stores into unsigned typed arrays that truncate the
613 // value into a Uint32 range.
614 bool IntegerInstructionSelector::IsUint32NarrowingDefinition(Definition* def) {
615 if (def->IsBinaryMintOp()) {
616 BinaryMintOpInstr* op = def->AsBinaryMintOp();
617 // Must be a mask operation.
618 if (op->op_kind() != Token::kBIT_AND) {
619 return false;
620 }
621 Range* range = op->range();
622 if ((range == NULL) ||
623 !range->IsWithin(0, static_cast<int64_t>(kMaxUint32))) {
624 return false;
625 }
626 return true;
627 }
628 // TODO(johnmccutchan): Add typed array stores.
629 return false;
630 }
631
632
633 void IntegerInstructionSelector::FindUint32NarrowingDefinitions() {
634 ASSERT(selected_uint32_defs_ != NULL);
635 if (FLAG_trace_integer_ir_selection) {
636 OS::Print("++++ Selecting Uint32 definitions:\n");
637 OS::Print("++++ Initial set:\n");
638 }
639 for (intptr_t i = 0; i < potential_uint32_defs_.length(); i++) {
640 Definition* defn = potential_uint32_defs_[i];
641 if (IsUint32NarrowingDefinition(defn)) {
642 if (FLAG_trace_integer_ir_selection) {
643 OS::Print("Adding %s\n", defn->ToCString());
644 }
645 selected_uint32_defs_->Add(defn->ssa_temp_index());
646 }
647 }
648 }
649
650
651 bool IntegerInstructionSelector::AllUsesAreUint32Narrowing(Value* list_head) {
652 for (Value::Iterator it(list_head);
653 !it.Done();
654 it.Advance()) {
655 Value* use = it.Current();
656 Definition* defn = use->instruction()->AsDefinition();
657 if ((defn == NULL) ||
658 (defn->ssa_temp_index() == -1) ||
659 !selected_uint32_defs_->Contains(defn->ssa_temp_index())) {
660 return false;
661 }
662 }
663 return true;
664 }
665
666
667 bool IntegerInstructionSelector::CanBecomeUint32(Definition* def) {
668 ASSERT(IsPotentialUint32Definition(def));
669 if (def->IsBoxInteger()) {
670 // If a BoxInteger's input is a candidate, the box is a candidate.
671 BoxIntegerInstr* box = def->AsBoxInteger();
672 Definition* box_input = box->value()->definition();
673 return selected_uint32_defs_->Contains(box_input->ssa_temp_index());
674 }
675 // A right shift with an input outside of Uint32 range cannot be converted
676 // because we need the high bits.
677 if (def->IsShiftMintOp()) {
678 ShiftMintOpInstr* op = def->AsShiftMintOp();
679 if (op->op_kind() == Token::kSHR) {
680 Definition* shift_input = op->left()->definition();
681 ASSERT(shift_input != NULL);
682 Range* range = shift_input->range();
683 if ((range == NULL) ||
684 !range->IsWithin(0, static_cast<int64_t>(kMaxUint32))) {
685 return false;
686 }
687 }
688 }
689 if (!def->HasUses()) {
690 // No uses, skip.
691 return false;
692 }
693 return AllUsesAreUint32Narrowing(def->input_use_list()) &&
694 AllUsesAreUint32Narrowing(def->env_use_list());
695 }
696
697
698 void IntegerInstructionSelector::Propagate() {
699 ASSERT(selected_uint32_defs_ != NULL);
700 bool changed = true;
701 intptr_t iteration = 0;
702 while (changed) {
703 if (FLAG_trace_integer_ir_selection) {
704 OS::Print("+++ Iteration: %" Pd "\n", iteration++);
705 }
706 changed = false;
707 for (intptr_t i = 0; i < potential_uint32_defs_.length(); i++) {
708 Definition* defn = potential_uint32_defs_[i];
709 if (selected_uint32_defs_->Contains(defn->ssa_temp_index())) {
710 // Already marked as a candidate, skip.
711 continue;
712 }
713 if (defn->IsConstant()) {
714 // Skip constants.
715 continue;
716 }
717 if (CanBecomeUint32(defn)) {
718 if (FLAG_trace_integer_ir_selection) {
719 OS::Print("Adding %s\n", defn->ToCString());
720 }
721 // Found a new candidate.
722 selected_uint32_defs_->Add(defn->ssa_temp_index());
723 // Haven't reached fixed point yet.
724 changed = true;
725 }
726 }
727 }
728 if (FLAG_trace_integer_ir_selection) {
729 OS::Print("Reached fixed point\n");
730 }
731 }
732
733
734 Definition* IntegerInstructionSelector::ConstructReplacementFor(
735 Definition* def) {
736 // Should only see mint definitions.
737 ASSERT(IsPotentialUint32Definition(def));
738 // Should not see constant instructions.
739 ASSERT(!def->IsConstant());
740 if (def->IsBinaryMintOp()) {
741 BinaryMintOpInstr* op = def->AsBinaryMintOp();
742 Token::Kind op_kind = op->op_kind();
743 Value* left = op->left()->CopyWithType();
744 Value* right = op->right()->CopyWithType();
745 intptr_t deopt_id = op->DeoptimizationTarget();
746 return new(I) BinaryUint32OpInstr(op_kind, left, right, deopt_id);
747 } else if (def->IsBoxInteger()) {
748 BoxIntegerInstr* box = def->AsBoxInteger();
749 Value* value = box->value()->CopyWithType();
750 return new(I) BoxUint32Instr(value);
751 } else if (def->IsUnboxInteger()) {
752 UnboxIntegerInstr* unbox = def->AsUnboxInteger();
753 Value* value = unbox->value()->CopyWithType();
754 intptr_t deopt_id = unbox->deopt_id();
755 return new(I) UnboxUint32Instr(value, deopt_id);
756 } else if (def->IsUnaryMintOp()) {
757 UnaryMintOpInstr* op = def->AsUnaryMintOp();
758 Token::Kind op_kind = op->op_kind();
759 Value* value = op->value()->CopyWithType();
760 intptr_t deopt_id = op->DeoptimizationTarget();
761 return new(I) UnaryUint32OpInstr(op_kind, value, deopt_id);
762 } else if (def->IsShiftMintOp()) {
763 ShiftMintOpInstr* op = def->AsShiftMintOp();
764 Token::Kind op_kind = op->op_kind();
765 Value* left = op->left()->CopyWithType();
766 Value* right = op->right()->CopyWithType();
767 intptr_t deopt_id = op->DeoptimizationTarget();
768 return new(I) ShiftUint32OpInstr(op_kind, left, right, deopt_id);
769 }
770 UNREACHABLE();
771 return NULL;
772 }
773
774
775 void IntegerInstructionSelector::ReplaceInstructions() {
776 if (FLAG_trace_integer_ir_selection) {
777 OS::Print("++++ Replacing instructions:\n");
778 }
779 for (intptr_t i = 0; i < potential_uint32_defs_.length(); i++) {
780 Definition* defn = potential_uint32_defs_[i];
781 if (!selected_uint32_defs_->Contains(defn->ssa_temp_index())) {
782 // Not a candidate.
783 continue;
784 }
785 Definition* replacement = ConstructReplacementFor(defn);
786 ASSERT(replacement != NULL);
787 if (FLAG_trace_integer_ir_selection) {
788 OS::Print("Replacing %s with %s\n", defn->ToCString(),
789 replacement->ToCString());
790 }
791 defn->ReplaceWith(replacement, NULL);
792 ASSERT(flow_graph_->VerifyUseLists());
793 }
794 }
795
796
797 RangeBoundary RangeBoundary::FromDefinition(Definition* defn, int64_t offs) {
798 if (defn->IsConstant() && defn->AsConstant()->value().IsSmi()) {
799 return FromConstant(Smi::Cast(defn->AsConstant()->value()).Value() + offs);
800 }
801 return RangeBoundary(kSymbol, reinterpret_cast<intptr_t>(defn), offs);
802 }
803
804
805 RangeBoundary RangeBoundary::LowerBound() const {
806 if (IsInfinity()) {
807 return NegativeInfinity();
808 }
809 if (IsConstant()) return *this;
810 return Add(Range::ConstantMin(symbol()->range()),
811 RangeBoundary::FromConstant(offset_),
812 NegativeInfinity());
813 }
814
815
816 RangeBoundary RangeBoundary::UpperBound() const {
817 if (IsInfinity()) {
818 return PositiveInfinity();
819 }
820 if (IsConstant()) return *this;
821 return Add(Range::ConstantMax(symbol()->range()),
822 RangeBoundary::FromConstant(offset_),
823 PositiveInfinity());
824 }
825
826
827 RangeBoundary RangeBoundary::Add(const RangeBoundary& a,
828 const RangeBoundary& b,
829 const RangeBoundary& overflow) {
830 if (a.IsInfinity() || b.IsInfinity()) return overflow;
831
832 ASSERT(a.IsConstant() && b.IsConstant());
833 if (Utils::WillAddOverflow(a.ConstantValue(), b.ConstantValue())) {
834 return overflow;
835 }
836
837 int64_t result = a.ConstantValue() + b.ConstantValue();
838
839 return RangeBoundary::FromConstant(result);
840 }
841
842
843 RangeBoundary RangeBoundary::Sub(const RangeBoundary& a,
844 const RangeBoundary& b,
845 const RangeBoundary& overflow) {
846 if (a.IsInfinity() || b.IsInfinity()) return overflow;
847 ASSERT(a.IsConstant() && b.IsConstant());
848 if (Utils::WillSubOverflow(a.ConstantValue(), b.ConstantValue())) {
849 return overflow;
850 }
851
852 int64_t result = a.ConstantValue() - b.ConstantValue();
853
854 return RangeBoundary::FromConstant(result);
855 }
856
857
858 bool RangeBoundary::SymbolicAdd(const RangeBoundary& a,
859 const RangeBoundary& b,
860 RangeBoundary* result) {
861 if (a.IsSymbol() && b.IsConstant()) {
862 if (Utils::WillAddOverflow(a.offset(), b.ConstantValue())) {
863 return false;
864 }
865
866 const int64_t offset = a.offset() + b.ConstantValue();
867
868 *result = RangeBoundary::FromDefinition(a.symbol(), offset);
869 return true;
870 } else if (b.IsSymbol() && a.IsConstant()) {
871 return SymbolicAdd(b, a, result);
872 }
873 return false;
874 }
875
876
877 bool RangeBoundary::SymbolicSub(const RangeBoundary& a,
878 const RangeBoundary& b,
879 RangeBoundary* result) {
880 if (a.IsSymbol() && b.IsConstant()) {
881 if (Utils::WillSubOverflow(a.offset(), b.ConstantValue())) {
882 return false;
883 }
884
885 const int64_t offset = a.offset() - b.ConstantValue();
886
887 *result = RangeBoundary::FromDefinition(a.symbol(), offset);
888 return true;
889 }
890 return false;
891 }
892
893
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 {
922 if (IsConstant() && other.IsConstant()) {
923 return ConstantValue() == other.ConstantValue();
924 } else if (IsInfinity() && other.IsInfinity()) {
925 return kind() == other.kind();
926 } else if (IsSymbol() && other.IsSymbol()) {
927 return (offset() == other.offset()) && DependOnSameSymbol(*this, other);
928 } else if (IsUnknown() && other.IsUnknown()) {
929 return true;
930 }
931 return false;
932 }
933
934
935 RangeBoundary RangeBoundary::Shl(const RangeBoundary& value_boundary,
936 int64_t shift_count,
937 const RangeBoundary& overflow) {
938 ASSERT(value_boundary.IsConstant());
939 ASSERT(shift_count >= 0);
940 int64_t limit = 64 - shift_count;
941 int64_t value = value_boundary.ConstantValue();
942
943 if ((value == 0) ||
944 (shift_count == 0) ||
945 ((limit > 0) && Utils::IsInt(static_cast<int>(limit), value))) {
946 // Result stays in 64 bit range.
947 int64_t result = value << shift_count;
948 return RangeBoundary(result);
949 }
950
951 return overflow;
952 }
953
954
955 static RangeBoundary CanonicalizeBoundary(const RangeBoundary& a,
956 const RangeBoundary& overflow) {
957 if (a.IsConstant() || a.IsInfinity()) {
958 return a;
959 }
960
961 int64_t offset = a.offset();
962 Definition* symbol = a.symbol();
963
964 bool changed;
965 do {
966 changed = false;
967 if (symbol->IsConstraint()) {
968 symbol = symbol->AsConstraint()->value()->definition();
969 changed = true;
970 } else if (symbol->IsBinarySmiOp()) {
971 BinarySmiOpInstr* op = symbol->AsBinarySmiOp();
972 Definition* left = op->left()->definition();
973 Definition* right = op->right()->definition();
974 switch (op->op_kind()) {
975 case Token::kADD:
976 if (right->IsConstant()) {
977 int64_t rhs = Smi::Cast(right->AsConstant()->value()).Value();
978 if (Utils::WillAddOverflow(offset, rhs)) {
979 return overflow;
980 }
981 offset += rhs;
982 symbol = left;
983 changed = true;
984 } else if (left->IsConstant()) {
985 int64_t rhs = Smi::Cast(left->AsConstant()->value()).Value();
986 if (Utils::WillAddOverflow(offset, rhs)) {
987 return overflow;
988 }
989 offset += rhs;
990 symbol = right;
991 changed = true;
992 }
993 break;
994
995 case Token::kSUB:
996 if (right->IsConstant()) {
997 int64_t rhs = Smi::Cast(right->AsConstant()->value()).Value();
998 if (Utils::WillSubOverflow(offset, rhs)) {
999 return overflow;
1000 }
1001 offset -= rhs;
1002 symbol = left;
1003 changed = true;
1004 }
1005 break;
1006
1007 default:
1008 break;
1009 }
1010 }
1011 } while (changed);
1012
1013 return RangeBoundary::FromDefinition(symbol, offset);
1014 }
1015
1016
1017 static bool CanonicalizeMaxBoundary(RangeBoundary* a) {
1018 if (!a->IsSymbol()) return false;
1019
1020 Range* range = a->symbol()->range();
1021 if ((range == NULL) || !range->max().IsSymbol()) return false;
1022
1023
1024 if (Utils::WillAddOverflow(range->max().offset(), a->offset())) {
1025 *a = RangeBoundary::PositiveInfinity();
1026 return true;
1027 }
1028
1029 const int64_t offset = range->max().offset() + a->offset();
1030
1031
1032 *a = CanonicalizeBoundary(
1033 RangeBoundary::FromDefinition(range->max().symbol(), offset),
1034 RangeBoundary::PositiveInfinity());
1035
1036 return true;
1037 }
1038
1039
1040 static bool CanonicalizeMinBoundary(RangeBoundary* a) {
1041 if (!a->IsSymbol()) return false;
1042
1043 Range* range = a->symbol()->range();
1044 if ((range == NULL) || !range->min().IsSymbol()) return false;
1045
1046 if (Utils::WillAddOverflow(range->min().offset(), a->offset())) {
1047 *a = RangeBoundary::NegativeInfinity();
1048 return true;
1049 }
1050
1051 const int64_t offset = range->min().offset() + a->offset();
1052
1053 *a = CanonicalizeBoundary(
1054 RangeBoundary::FromDefinition(range->min().symbol(), offset),
1055 RangeBoundary::NegativeInfinity());
1056
1057 return true;
1058 }
1059
1060
1061 RangeBoundary RangeBoundary::Min(RangeBoundary a, RangeBoundary b,
1062 RangeSize size) {
1063 ASSERT(!(a.IsNegativeInfinity() || b.IsNegativeInfinity()));
1064 ASSERT(!a.IsUnknown() || !b.IsUnknown());
1065 if (a.IsUnknown() && !b.IsUnknown()) {
1066 return b;
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 }
1087
1088 if (a.Equals(b)) {
1089 return b;
1090 }
1091
1092 {
1093 RangeBoundary canonical_a =
1094 CanonicalizeBoundary(a, RangeBoundary::PositiveInfinity());
1095 RangeBoundary canonical_b =
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;
1109 }
1110
1111 const int64_t min_a = a.UpperBound().Clamp(size).ConstantValue();
1112 const int64_t min_b = b.UpperBound().Clamp(size).ConstantValue();
1113
1114 return RangeBoundary::FromConstant(Utils::Minimum(min_a, min_b));
1115 }
1116
1117
1118 RangeBoundary RangeBoundary::Max(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)) {
1145 return b;
1146 }
1147
1148 {
1149 RangeBoundary canonical_a =
1150 CanonicalizeBoundary(a, RangeBoundary::NegativeInfinity());
1151 RangeBoundary canonical_b =
1152 CanonicalizeBoundary(b, RangeBoundary::NegativeInfinity());
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 }
1163
1164 if (DependOnSameSymbol(a, b)) {
1165 return (a.offset() <= b.offset()) ? b : a;
1166 }
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 }
1173
1174
1175 int64_t RangeBoundary::ConstantValue() const {
1176 ASSERT(IsConstant());
1177 return value_;
1178 }
1179
1180
1181 bool Range::IsPositive() const {
1182 if (min().IsNegativeInfinity()) {
1183 return false;
1184 }
1185 if (min().LowerBound().ConstantValue() < 0) {
1186 return false;
1187 }
1188 if (max().IsPositiveInfinity()) {
1189 return true;
1190 }
1191 return max().UpperBound().ConstantValue() >= 0;
1192 }
1193
1194
1195 bool Range::OnlyLessThanOrEqualTo(int64_t val) const {
1196 if (max().IsPositiveInfinity()) {
1197 // Cannot be true.
1198 return false;
1199 }
1200 if (max().UpperBound().ConstantValue() > val) {
1201 // Not true.
1202 return false;
1203 }
1204 return true;
1205 }
1206
1207
1208 bool Range::OnlyGreaterThanOrEqualTo(int64_t val) const {
1209 if (min().IsNegativeInfinity()) {
1210 return false;
1211 }
1212 if (min().LowerBound().ConstantValue() < val) {
1213 return false;
1214 }
1215 return true;
1216 }
1217
1218
1219 // Inclusive.
1220 bool Range::IsWithin(int64_t min_int, int64_t max_int) const {
1221 RangeBoundary lower_min = min().LowerBound();
1222 if (lower_min.IsNegativeInfinity() || (lower_min.ConstantValue() < min_int)) {
1223 return false;
1224 }
1225 RangeBoundary upper_max = max().UpperBound();
1226 if (upper_max.IsPositiveInfinity() || (upper_max.ConstantValue() > max_int)) {
1227 return false;
1228 }
1229 return true;
1230 }
1231
1232
1233 bool Range::Overlaps(int64_t min_int, int64_t max_int) const {
1234 RangeBoundary lower = min().LowerBound();
1235 RangeBoundary upper = max().UpperBound();
1236 const int64_t this_min = lower.IsNegativeInfinity() ?
1237 RangeBoundary::kMin : lower.ConstantValue();
1238 const int64_t this_max = upper.IsPositiveInfinity() ?
1239 RangeBoundary::kMax : upper.ConstantValue();
1240 if ((this_min <= min_int) && (min_int <= this_max)) return true;
1241 if ((this_min <= max_int) && (max_int <= this_max)) return true;
1242 if ((min_int < this_min) && (max_int > this_max)) return true;
1243 return false;
1244 }
1245
1246
1247 bool Range::IsUnsatisfiable() const {
1248 // Infinity case: [+inf, ...] || [..., -inf]
1249 if (min().IsPositiveInfinity() || max().IsNegativeInfinity()) {
1250 return true;
1251 }
1252 // Constant case: For example [0, -1].
1253 if (Range::ConstantMin(this).ConstantValue() >
1254 Range::ConstantMax(this).ConstantValue()) {
1255 return true;
1256 }
1257 // Symbol case: For example [v+1, v].
1258 if (DependOnSameSymbol(min(), max()) && min().offset() > max().offset()) {
1259 return true;
1260 }
1261 return false;
1262 }
1263
1264
1265 void Range::Clamp(RangeBoundary::RangeSize size) {
1266 min_ = min_.Clamp(size);
1267 max_ = max_.Clamp(size);
1268 }
1269
1270
1271 void Range::Shl(const Range* left,
1272 const Range* right,
1273 RangeBoundary* result_min,
1274 RangeBoundary* result_max) {
1275 ASSERT(left != NULL);
1276 ASSERT(right != NULL);
1277 ASSERT(result_min != NULL);
1278 ASSERT(result_max != NULL);
1279 RangeBoundary left_max = Range::ConstantMax(left);
1280 RangeBoundary left_min = Range::ConstantMin(left);
1281 // A negative shift count always deoptimizes (and throws), so the minimum
1282 // shift count is zero.
1283 int64_t right_max = Utils::Maximum(Range::ConstantMax(right).ConstantValue(),
1284 static_cast<int64_t>(0));
1285 int64_t right_min = Utils::Maximum(Range::ConstantMin(right).ConstantValue(),
1286 static_cast<int64_t>(0));
1287
1288 *result_min = RangeBoundary::Shl(
1289 left_min,
1290 left_min.ConstantValue() > 0 ? right_min : right_max,
1291 left_min.ConstantValue() > 0
1292 ? RangeBoundary::PositiveInfinity()
1293 : RangeBoundary::NegativeInfinity());
1294
1295 *result_max = RangeBoundary::Shl(
1296 left_max,
1297 left_max.ConstantValue() > 0 ? right_max : right_min,
1298 left_max.ConstantValue() > 0
1299 ? RangeBoundary::PositiveInfinity()
1300 : RangeBoundary::NegativeInfinity());
1301 }
1302
1303
1304 void Range::Shr(const Range* left,
1305 const Range* right,
1306 RangeBoundary* result_min,
1307 RangeBoundary* result_max) {
1308 RangeBoundary left_max = Range::ConstantMax(left);
1309 RangeBoundary left_min = Range::ConstantMin(left);
1310 // A negative shift count always deoptimizes (and throws), so the minimum
1311 // shift count is zero.
1312 int64_t right_max = Utils::Maximum(Range::ConstantMax(right).ConstantValue(),
1313 static_cast<int64_t>(0));
1314 int64_t right_min = Utils::Maximum(Range::ConstantMin(right).ConstantValue(),
1315 static_cast<int64_t>(0));
1316
1317 *result_min = RangeBoundary::Shr(
1318 left_min,
1319 left_min.ConstantValue() > 0 ? right_max : right_min);
1320
1321 *result_max = RangeBoundary::Shr(
1322 left_max,
1323 left_max.ConstantValue() > 0 ? right_min : right_max);
1324 }
1325
1326
1327 bool Range::And(const Range* left_range,
1328 const Range* right_range,
1329 RangeBoundary* result_min,
1330 RangeBoundary* result_max) {
1331 ASSERT(left_range != NULL);
1332 ASSERT(right_range != NULL);
1333 ASSERT(result_min != NULL);
1334 ASSERT(result_max != NULL);
1335
1336 if (Range::ConstantMin(right_range).ConstantValue() >= 0) {
1337 *result_min = RangeBoundary::FromConstant(0);
1338 *result_max = Range::ConstantMax(right_range);
1339 return true;
1340 }
1341
1342 if (Range::ConstantMin(left_range).ConstantValue() >= 0) {
1343 *result_min = RangeBoundary::FromConstant(0);
1344 *result_max = Range::ConstantMax(left_range);
1345 return true;
1346 }
1347
1348 return false;
1349 }
1350
1351
1352 static bool IsArrayLength(Definition* defn) {
1353 if (defn == NULL) {
1354 return false;
1355 }
1356 LoadFieldInstr* load = defn->AsLoadField();
1357 return (load != NULL) && load->IsImmutableLengthLoad();
1358 }
1359
1360
1361 void Range::Add(const Range* left_range,
1362 const Range* right_range,
1363 RangeBoundary* result_min,
1364 RangeBoundary* result_max,
1365 Definition* left_defn) {
1366 ASSERT(left_range != NULL);
1367 ASSERT(right_range != NULL);
1368 ASSERT(result_min != NULL);
1369 ASSERT(result_max != NULL);
1370
1371 RangeBoundary left_min =
1372 IsArrayLength(left_defn) ?
1373 RangeBoundary::FromDefinition(left_defn) : left_range->min();
1374
1375 RangeBoundary left_max =
1376 IsArrayLength(left_defn) ?
1377 RangeBoundary::FromDefinition(left_defn) : left_range->max();
1378
1379 if (!RangeBoundary::SymbolicAdd(left_min, right_range->min(), result_min)) {
1380 *result_min = RangeBoundary::Add(left_range->min().LowerBound(),
1381 right_range->min().LowerBound(),
1382 RangeBoundary::NegativeInfinity());
1383 }
1384 if (!RangeBoundary::SymbolicAdd(left_max, right_range->max(), result_max)) {
1385 *result_max = RangeBoundary::Add(right_range->max().UpperBound(),
1386 left_range->max().UpperBound(),
1387 RangeBoundary::PositiveInfinity());
1388 }
1389 }
1390
1391
1392 void Range::Sub(const Range* left_range,
1393 const Range* right_range,
1394 RangeBoundary* result_min,
1395 RangeBoundary* result_max,
1396 Definition* left_defn) {
1397 ASSERT(left_range != NULL);
1398 ASSERT(right_range != NULL);
1399 ASSERT(result_min != NULL);
1400 ASSERT(result_max != NULL);
1401
1402 RangeBoundary left_min =
1403 IsArrayLength(left_defn) ?
1404 RangeBoundary::FromDefinition(left_defn) : left_range->min();
1405
1406 RangeBoundary left_max =
1407 IsArrayLength(left_defn) ?
1408 RangeBoundary::FromDefinition(left_defn) : left_range->max();
1409
1410 if (!RangeBoundary::SymbolicSub(left_min, right_range->max(), result_min)) {
1411 *result_min = RangeBoundary::Sub(left_range->min().LowerBound(),
1412 right_range->max().UpperBound(),
1413 RangeBoundary::NegativeInfinity());
1414 }
1415 if (!RangeBoundary::SymbolicSub(left_max, right_range->min(), result_max)) {
1416 *result_max = RangeBoundary::Sub(left_range->max().UpperBound(),
1417 right_range->min().LowerBound(),
1418 RangeBoundary::PositiveInfinity());
1419 }
1420 }
1421
1422
1423 bool Range::Mul(const Range* left_range,
1424 const Range* right_range,
1425 RangeBoundary* result_min,
1426 RangeBoundary* result_max) {
1427 ASSERT(left_range != NULL);
1428 ASSERT(right_range != NULL);
1429 ASSERT(result_min != NULL);
1430 ASSERT(result_max != NULL);
1431
1432 const int64_t left_max = ConstantAbsMax(left_range);
1433 const int64_t right_max = ConstantAbsMax(right_range);
1434 if ((left_max <= -kSmiMin) && (right_max <= -kSmiMin) &&
1435 ((left_max == 0) || (right_max <= kMaxInt64 / left_max))) {
1436 // Product of left and right max values stays in 64 bit range.
1437 const int64_t mul_max = left_max * right_max;
1438 if (Smi::IsValid(mul_max) && Smi::IsValid(-mul_max)) {
1439 const int64_t r_min =
1440 OnlyPositiveOrZero(*left_range, *right_range) ? 0 : -mul_max;
1441 *result_min = RangeBoundary::FromConstant(r_min);
1442 const int64_t r_max =
1443 OnlyNegativeOrZero(*left_range, *right_range) ? 0 : mul_max;
1444 *result_max = RangeBoundary::FromConstant(r_max);
1445 return true;
1446 }
1447 }
1448 return false;
1449 }
1450
1451
1452 // Both the a and b ranges are >= 0.
1453 bool Range::OnlyPositiveOrZero(const Range& a, const Range& b) {
1454 return a.OnlyGreaterThanOrEqualTo(0) && b.OnlyGreaterThanOrEqualTo(0);
1455 }
1456
1457
1458 // Both the a and b ranges are <= 0.
1459 bool Range::OnlyNegativeOrZero(const Range& a, const Range& b) {
1460 return a.OnlyLessThanOrEqualTo(0) && b.OnlyLessThanOrEqualTo(0);
1461 }
1462
1463
1464 // Return the maximum absolute value included in range.
1465 int64_t Range::ConstantAbsMax(const Range* range) {
1466 if (range == NULL) {
1467 return RangeBoundary::kMax;
1468 }
1469 const int64_t abs_min = Utils::Abs(Range::ConstantMin(range).ConstantValue());
1470 const int64_t abs_max = Utils::Abs(Range::ConstantMax(range).ConstantValue());
1471 return Utils::Maximum(abs_min, abs_max);
1472 }
1473
1474
1475 Range* Range::BinaryOp(const Token::Kind op,
1476 const Range* left_range,
1477 const Range* right_range,
1478 Definition* left_defn) {
1479 ASSERT(left_range != NULL);
1480 ASSERT(right_range != NULL);
1481
1482 // Both left and right ranges are finite.
1483 ASSERT(left_range->IsFinite());
1484 ASSERT(right_range->IsFinite());
1485
1486 RangeBoundary min;
1487 RangeBoundary max;
1488 ASSERT(min.IsUnknown() && max.IsUnknown());
1489
1490 switch (op) {
1491 case Token::kADD:
1492 Range::Add(left_range, right_range, &min, &max, left_defn);
1493 break;
1494 case Token::kSUB:
1495 Range::Sub(left_range, right_range, &min, &max, left_defn);
1496 break;
1497 case Token::kMUL: {
1498 if (!Range::Mul(left_range, right_range, &min, &max)) {
1499 return NULL;
1500 }
1501 break;
1502 }
1503 case Token::kSHL: {
1504 Range::Shl(left_range, right_range, &min, &max);
1505 break;
1506 }
1507 case Token::kSHR: {
1508 Range::Shr(left_range, right_range, &min, &max);
1509 break;
1510 }
1511 case Token::kBIT_AND:
1512 if (!Range::And(left_range, right_range, &min, &max)) {
1513 return NULL;
1514 }
1515 break;
1516 default:
1517 return NULL;
1518 break;
1519 }
1520
1521 ASSERT(!min.IsUnknown() && !max.IsUnknown());
1522
1523 return new Range(min, max);
1524 }
1525
1526
1527 void Definition::InferRange() {
1528 if (Type()->ToCid() == kSmiCid) {
1529 if (range_ == NULL) {
1530 range_ = Range::UnknownSmi();
1531 }
1532 } else if (IsMintDefinition()) {
1533 if (range_ == NULL) {
1534 range_ = Range::Unknown();
1535 }
1536 } else {
1537 // Only Smi and Mint supported.
1538 UNREACHABLE();
1539 }
1540 }
1541
1542
1543 void PhiInstr::InferRange() {
1544 RangeBoundary new_min;
1545 RangeBoundary new_max;
1546
1547 ASSERT(Type()->ToCid() == kSmiCid);
1548
1549 for (intptr_t i = 0; i < InputCount(); i++) {
1550 Range* input_range = InputAt(i)->definition()->range();
1551 if (input_range == NULL) {
1552 range_ = Range::UnknownSmi();
1553 return;
1554 }
1555
1556 if (new_min.IsUnknown()) {
1557 new_min = Range::ConstantMin(input_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;
1577 }
1578
1579 range_ = new Range(new_min, new_max);
1580 }
1581
1582
1583 void ConstantInstr::InferRange() {
1584 if (value_.IsSmi()) {
1585 if (range_ == NULL) {
1586 int64_t value = Smi::Cast(value_).Value();
1587 range_ = new Range(RangeBoundary::FromConstant(value),
1588 RangeBoundary::FromConstant(value));
1589 }
1590 } else if (value_.IsMint()) {
1591 if (range_ == NULL) {
1592 int64_t value = Mint::Cast(value_).value();
1593 range_ = new Range(RangeBoundary::FromConstant(value),
1594 RangeBoundary::FromConstant(value));
1595 }
1596 } else {
1597 // Only Smi and Mint supported.
1598 UNREACHABLE();
1599 }
1600 }
1601
1602
1603 void UnboxIntegerInstr::InferRange() {
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.
1621 ASSERT(value()->IsSmiValue());
1622
1623 RangeBoundary min;
1624 RangeBoundary max;
1625
1626 {
1627 RangeBoundary value_min = (value_range == NULL) ?
1628 RangeBoundary() : value_range->min();
1629 RangeBoundary constraint_min = constraint()->min();
1630 min = RangeBoundary::Max(value_min, constraint_min,
1631 RangeBoundary::kRangeBoundarySmi);
1632 }
1633
1634 ASSERT(!min.IsUnknown());
1635
1636 {
1637 RangeBoundary value_max = (value_range == NULL) ?
1638 RangeBoundary() : value_range->max();
1639 RangeBoundary constraint_max = constraint()->max();
1640 max = RangeBoundary::Min(value_max, constraint_max,
1641 RangeBoundary::kRangeBoundarySmi);
1642 }
1643
1644 ASSERT(!max.IsUnknown());
1645
1646 range_ = new Range(min, max);
1647
1648 // Mark branches that generate unsatisfiable constraints as constant.
1649 if (target() != NULL && range_->IsUnsatisfiable()) {
1650 BranchInstr* branch =
1651 target()->PredecessorAt(0)->last_instruction()->AsBranch();
1652 if (target() == branch->true_successor()) {
1653 // True unreachable.
1654 if (FLAG_trace_constant_propagation) {
1655 OS::Print("Range analysis: True unreachable (B%" Pd ")\n",
1656 branch->true_successor()->block_id());
1657 }
1658 branch->set_constant_target(branch->false_successor());
1659 } else {
1660 ASSERT(target() == branch->false_successor());
1661 // False unreachable.
1662 if (FLAG_trace_constant_propagation) {
1663 OS::Print("Range analysis: False unreachable (B%" Pd ")\n",
1664 branch->false_successor()->block_id());
1665 }
1666 branch->set_constant_target(branch->true_successor());
1667 }
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()) {
1698 case kTypedDataInt8ArrayCid:
1699 range_ = new Range(RangeBoundary::FromConstant(-128),
1700 RangeBoundary::FromConstant(127));
1701 break;
1702 case kTypedDataUint8ArrayCid:
1703 case kTypedDataUint8ClampedArrayCid:
1704 case kExternalTypedDataUint8ArrayCid:
1705 case kExternalTypedDataUint8ClampedArrayCid:
1706 range_ = new Range(RangeBoundary::FromConstant(0),
1707 RangeBoundary::FromConstant(255));
1708 break;
1709 case kTypedDataInt16ArrayCid:
1710 range_ = new Range(RangeBoundary::FromConstant(-32768),
1711 RangeBoundary::FromConstant(32767));
1712 break;
1713 case kTypedDataUint16ArrayCid:
1714 range_ = new Range(RangeBoundary::FromConstant(0),
1715 RangeBoundary::FromConstant(65535));
1716 break;
1717 case kTypedDataInt32ArrayCid:
1718 if (Typed32BitIsSmi()) {
1719 range_ = Range::UnknownSmi();
1720 } else {
1721 range_ = new Range(RangeBoundary::FromConstant(kMinInt32),
1722 RangeBoundary::FromConstant(kMaxInt32));
1723 }
1724 break;
1725 case kTypedDataUint32ArrayCid:
1726 if (Typed32BitIsSmi()) {
1727 range_ = Range::UnknownSmi();
1728 } else {
1729 range_ = new Range(RangeBoundary::FromConstant(0),
1730 RangeBoundary::FromConstant(kMaxUint32));
1731 }
1732 break;
1733 case kOneByteStringCid:
1734 range_ = new Range(RangeBoundary::FromConstant(0),
1735 RangeBoundary::FromConstant(0xFF));
1736 break;
1737 case kTwoByteStringCid:
1738 range_ = new Range(RangeBoundary::FromConstant(0),
1739 RangeBoundary::FromConstant(0xFFFF));
1740 break;
1741 default:
1742 Definition::InferRange();
1743 break;
1744 }
1745 }
1746
1747
1748 void IfThenElseInstr::InferRange() {
1749 const intptr_t min = Utils::Minimum(if_true_, if_false_);
1750 const intptr_t max = Utils::Maximum(if_true_, if_false_);
1751 range_ = new Range(RangeBoundary::FromConstant(min),
1752 RangeBoundary::FromConstant(max));
1753 }
1754
1755
1756 void BinarySmiOpInstr::InferRange() {
1757 // TODO(vegorov): canonicalize BinarySmiOp to always have constant on the
1758 // right and a non-constant on the left.
1759 Definition* left_defn = left()->definition();
1760
1761 Range* left_range = left_defn->range();
1762 Range* right_range = right()->definition()->range();
1763
1764 if ((left_range == NULL) || (right_range == NULL)) {
1765 range_ = Range::UnknownSmi();
1766 return;
1767 }
1768
1769 Range* possible_range = Range::BinaryOp(op_kind(),
1770 left_range,
1771 right_range,
1772 left_defn);
1773
1774 if ((range_ == NULL) && (possible_range == NULL)) {
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.
1789 const bool overflowed = range_->min().LowerBound().OverflowedSmi() ||
1790 range_->max().UpperBound().OverflowedSmi();
1791 set_overflow(overflowed);
1792
1793 // Clamp value to be within smi range.
1794 range_->Clamp(RangeBoundary::kRangeBoundarySmi);
1795 }
1796
1797
1798 void BinaryMintOpInstr::InferRange() {
1799 // TODO(vegorov): canonicalize BinaryMintOpInstr to always have constant on
1800 // the right and a non-constant on the left.
1801 Definition* left_defn = left()->definition();
1802
1803 Range* left_range = left_defn->range();
1804 Range* right_range = right()->definition()->range();
1805
1806 if ((left_range == NULL) || (right_range == NULL)) {
1807 range_ = Range::Unknown();
1808 return;
1809 }
1810
1811 Range* possible_range = Range::BinaryOp(op_kind(),
1812 left_range,
1813 right_range,
1814 left_defn);
1815
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
1831 // Calculate overflowed status before clamping.
1832 const bool overflowed = range_->min().LowerBound().OverflowedMint() ||
1833 range_->max().UpperBound().OverflowedMint();
1834 set_can_overflow(overflowed);
1835
1836 // Clamp value to be within mint range.
1837 range_->Clamp(RangeBoundary::kRangeBoundaryInt64);
1838 }
1839
1840
1841 void ShiftMintOpInstr::InferRange() {
1842 Definition* left_defn = left()->definition();
1843
1844 Range* left_range = left_defn->range();
1845 Range* right_range = right()->definition()->range();
1846
1847 if ((left_range == NULL) || (right_range == NULL)) {
1848 range_ = Range::Unknown();
1849 return;
1850 }
1851
1852 Range* possible_range = Range::BinaryOp(op_kind(),
1853 left_range,
1854 right_range,
1855 left_defn);
1856
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
1872 // Calculate overflowed status before clamping.
1873 const bool overflowed = range_->min().LowerBound().OverflowedMint() ||
1874 range_->max().UpperBound().OverflowedMint();
1875 set_can_overflow(overflowed);
1876
1877 // Clamp value to be within mint range.
1878 range_->Clamp(RangeBoundary::kRangeBoundaryInt64);
1879 }
1880
1881
1882 void BoxIntegerInstr::InferRange() {
1883 Range* input_range = value()->definition()->range();
1884 if (input_range != NULL) {
1885 bool is_smi = !input_range->min().LowerBound().OverflowedSmi() &&
1886 !input_range->max().UpperBound().OverflowedSmi();
1887 set_is_smi(is_smi);
1888 // The output range is the same as the input range.
1889 range_ = input_range;
1890 }
1891 }
1892
1893
1894 bool CheckArrayBoundInstr::IsRedundant(const RangeBoundary& length) {
1895 Range* index_range = index()->definition()->range();
1896
1897 // Range of the index is unknown can't decide if the check is redundant.
1898 if (index_range == NULL) {
1899 return false;
1900 }
1901
1902 // Range of the index is not positive. Check can't be redundant.
1903 if (Range::ConstantMinSmi(index_range).ConstantValue() < 0) {
1904 return false;
1905 }
1906
1907 RangeBoundary max = CanonicalizeBoundary(index_range->max(),
1908 RangeBoundary::PositiveInfinity());
1909
1910 if (max.OverflowedSmi()) {
1911 return false;
1912 }
1913
1914
1915 RangeBoundary max_upper = max.UpperBound();
1916 RangeBoundary length_lower = length.LowerBound();
1917
1918 if (max_upper.OverflowedSmi() || length_lower.OverflowedSmi()) {
1919 return false;
1920 }
1921
1922 // Try to compare constant boundaries.
1923 if (max_upper.ConstantValue() < length_lower.ConstantValue()) {
1924 return true;
1925 }
1926
1927 RangeBoundary canonical_length =
1928 CanonicalizeBoundary(length, RangeBoundary::PositiveInfinity());
1929 if (canonical_length.OverflowedSmi()) {
1930 return false;
1931 }
1932
1933 // Try symbolic comparison.
1934 do {
1935 if (DependOnSameSymbol(max, canonical_length)) {
1936 return max.offset() < canonical_length.offset();
1937 }
1938 } while (CanonicalizeMaxBoundary(&max) ||
1939 CanonicalizeMinBoundary(&canonical_length));
1940
1941 // Failed to prove that maximum is bounded with array length.
1942 return false;
1943 }
1944
1945
1946 } // 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