Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 |
| OLD | NEW |