V8 Project
hydrogen-range-analysis.cc
Go to the documentation of this file.
1 // Copyright 2013 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
6 
7 namespace v8 {
8 namespace internal {
9 
10 
11 class Pending {
12  public:
13  Pending(HBasicBlock* block, int last_changed_range)
15 
16  HBasicBlock* block() const { return block_; }
17  int last_changed_range() const { return last_changed_range_; }
18 
19  private:
20  HBasicBlock* block_;
22 };
23 
24 
25 void HRangeAnalysisPhase::TraceRange(const char* msg, ...) {
26  if (FLAG_trace_range) {
27  va_list arguments;
28  va_start(arguments, msg);
29  base::OS::VPrint(msg, arguments);
30  va_end(arguments);
31  }
32 }
33 
34 
36  HBasicBlock* block(graph()->entry_block());
37  ZoneList<Pending> stack(graph()->blocks()->length(), zone());
38  while (block != NULL) {
39  TraceRange("Analyzing block B%d\n", block->block_id());
40 
41  // Infer range based on control flow.
42  if (block->predecessors()->length() == 1) {
43  HBasicBlock* pred = block->predecessors()->first();
44  if (pred->end()->IsCompareNumericAndBranch()) {
46  block);
47  }
48  }
49 
50  // Process phi instructions.
51  for (int i = 0; i < block->phis()->length(); ++i) {
52  HPhi* phi = block->phis()->at(i);
53  InferRange(phi);
54  }
55 
56  // Go through all instructions of the current block.
57  for (HInstructionIterator it(block); !it.Done(); it.Advance()) {
58  HValue* value = it.Current();
59  InferRange(value);
60 
61  // Compute the bailout-on-minus-zero flag.
62  if (value->IsChange()) {
63  HChange* instr = HChange::cast(value);
64  // Propagate flags for negative zero checks upwards from conversions
65  // int32-to-tagged and int32-to-double.
66  Representation from = instr->value()->representation();
67  DCHECK(from.Equals(instr->from()));
68  if (from.IsSmiOrInteger32()) {
69  DCHECK(instr->to().IsTagged() ||
70  instr->to().IsDouble() ||
71  instr->to().IsSmiOrInteger32());
72  PropagateMinusZeroChecks(instr->value());
73  }
74  } else if (value->IsCompareMinusZeroAndBranch()) {
75  HCompareMinusZeroAndBranch* instr =
76  HCompareMinusZeroAndBranch::cast(value);
77  if (instr->value()->representation().IsSmiOrInteger32()) {
78  PropagateMinusZeroChecks(instr->value());
79  }
80  }
81  }
82 
83  // Continue analysis in all dominated blocks.
84  const ZoneList<HBasicBlock*>* dominated_blocks(block->dominated_blocks());
85  if (!dominated_blocks->is_empty()) {
86  // Continue with first dominated block, and push the
87  // remaining blocks on the stack (in reverse order).
88  int last_changed_range = changed_ranges_.length();
89  for (int i = dominated_blocks->length() - 1; i > 0; --i) {
90  stack.Add(Pending(dominated_blocks->at(i), last_changed_range), zone());
91  }
92  block = dominated_blocks->at(0);
93  } else if (!stack.is_empty()) {
94  // Pop next pending block from stack.
95  Pending pending = stack.RemoveLast();
96  RollBackTo(pending.last_changed_range());
97  block = pending.block();
98  } else {
99  // All blocks done.
100  block = NULL;
101  }
102  }
103 
104  // The ranges are not valid anymore due to SSI vs. SSA!
105  PoisonRanges();
106 }
107 
108 
110 #ifdef DEBUG
111  for (int i = 0; i < graph()->blocks()->length(); ++i) {
112  HBasicBlock* block = graph()->blocks()->at(i);
113  for (HInstructionIterator it(block); !it.Done(); it.Advance()) {
114  HInstruction* instr = it.Current();
115  if (instr->HasRange()) instr->PoisonRange();
116  }
117  }
118 #endif
119 }
120 
121 
123  HBasicBlock* dest) {
124  DCHECK((test->FirstSuccessor() == dest) == (test->SecondSuccessor() != dest));
125  if (test->representation().IsSmiOrInteger32()) {
126  Token::Value op = test->token();
127  if (test->SecondSuccessor() == dest) {
128  op = Token::NegateCompareOp(op);
129  }
130  Token::Value inverted_op = Token::ReverseCompareOp(op);
131  UpdateControlFlowRange(op, test->left(), test->right());
132  UpdateControlFlowRange(inverted_op, test->right(), test->left());
133  }
134 }
135 
136 
137 // We know that value [op] other. Use this information to update the range on
138 // value.
140  HValue* value,
141  HValue* other) {
142  Range temp_range;
143  Range* range = other->range() != NULL ? other->range() : &temp_range;
144  Range* new_range = NULL;
145 
146  TraceRange("Control flow range infer %d %s %d\n",
147  value->id(),
148  Token::Name(op),
149  other->id());
150 
151  if (op == Token::EQ || op == Token::EQ_STRICT) {
152  // The same range has to apply for value.
153  new_range = range->Copy(graph()->zone());
154  } else if (op == Token::LT || op == Token::LTE) {
155  new_range = range->CopyClearLower(graph()->zone());
156  if (op == Token::LT) {
157  new_range->AddConstant(-1);
158  }
159  } else if (op == Token::GT || op == Token::GTE) {
160  new_range = range->CopyClearUpper(graph()->zone());
161  if (op == Token::GT) {
162  new_range->AddConstant(1);
163  }
164  }
165 
166  if (new_range != NULL && !new_range->IsMostGeneric()) {
167  AddRange(value, new_range);
168  }
169 }
170 
171 
173  DCHECK(!value->HasRange());
174  if (!value->representation().IsNone()) {
175  value->ComputeInitialRange(graph()->zone());
176  Range* range = value->range();
177  TraceRange("Initial inferred range of %d (%s) set to [%d,%d]\n",
178  value->id(),
179  value->Mnemonic(),
180  range->lower(),
181  range->upper());
182  }
183 }
184 
185 
187  DCHECK(index <= changed_ranges_.length());
188  for (int i = index; i < changed_ranges_.length(); ++i) {
189  changed_ranges_[i]->RemoveLastAddedRange();
190  }
191  changed_ranges_.Rewind(index);
192 }
193 
194 
195 void HRangeAnalysisPhase::AddRange(HValue* value, Range* range) {
196  Range* original_range = value->range();
197  value->AddNewRange(range, graph()->zone());
198  changed_ranges_.Add(value, zone());
199  Range* new_range = value->range();
200  TraceRange("Updated range of %d set to [%d,%d]\n",
201  value->id(),
202  new_range->lower(),
203  new_range->upper());
204  if (original_range != NULL) {
205  TraceRange("Original range was [%d,%d]\n",
206  original_range->lower(),
207  original_range->upper());
208  }
209  TraceRange("New information was [%d,%d]\n",
210  range->lower(),
211  range->upper());
212 }
213 
214 
216  DCHECK(worklist_.is_empty());
218 
219  AddToWorklist(value);
220  while (!worklist_.is_empty()) {
221  value = worklist_.RemoveLast();
222 
223  if (value->IsPhi()) {
224  // For phis, we must propagate the check to all of its inputs.
225  HPhi* phi = HPhi::cast(value);
226  for (int i = 0; i < phi->OperandCount(); ++i) {
227  AddToWorklist(phi->OperandAt(i));
228  }
229  } else if (value->IsUnaryMathOperation()) {
230  HUnaryMathOperation* instr = HUnaryMathOperation::cast(value);
231  if (instr->representation().IsSmiOrInteger32() &&
232  !instr->value()->representation().Equals(instr->representation())) {
233  if (instr->value()->range() == NULL ||
234  instr->value()->range()->CanBeMinusZero()) {
235  instr->SetFlag(HValue::kBailoutOnMinusZero);
236  }
237  }
238  if (instr->RequiredInputRepresentation(0).IsSmiOrInteger32() &&
239  instr->representation().Equals(
240  instr->RequiredInputRepresentation(0))) {
241  AddToWorklist(instr->value());
242  }
243  } else if (value->IsChange()) {
244  HChange* instr = HChange::cast(value);
245  if (!instr->from().IsSmiOrInteger32() &&
246  !instr->CanTruncateToInt32() &&
247  (instr->value()->range() == NULL ||
248  instr->value()->range()->CanBeMinusZero())) {
249  instr->SetFlag(HValue::kBailoutOnMinusZero);
250  }
251  } else if (value->IsForceRepresentation()) {
252  HForceRepresentation* instr = HForceRepresentation::cast(value);
253  AddToWorklist(instr->value());
254  } else if (value->IsMod()) {
255  HMod* instr = HMod::cast(value);
256  if (instr->range() == NULL || instr->range()->CanBeMinusZero()) {
257  instr->SetFlag(HValue::kBailoutOnMinusZero);
258  AddToWorklist(instr->left());
259  }
260  } else if (value->IsDiv() || value->IsMul()) {
262  if (instr->range() == NULL || instr->range()->CanBeMinusZero()) {
264  }
265  AddToWorklist(instr->right());
266  AddToWorklist(instr->left());
267  } else if (value->IsMathFloorOfDiv()) {
268  HMathFloorOfDiv* instr = HMathFloorOfDiv::cast(value);
269  instr->SetFlag(HValue::kBailoutOnMinusZero);
270  } else if (value->IsAdd() || value->IsSub()) {
272  if (instr->range() == NULL || instr->range()->CanBeMinusZero()) {
273  // Propagate to the left argument. If the left argument cannot be -0,
274  // then the result of the add/sub operation cannot be either.
275  AddToWorklist(instr->left());
276  }
277  } else if (value->IsMathMinMax()) {
278  HMathMinMax* instr = HMathMinMax::cast(value);
279  AddToWorklist(instr->right());
280  AddToWorklist(instr->left());
281  }
282  }
283 
286  DCHECK(worklist_.is_empty());
287 }
288 
289 
290 } } // namespace v8::internal
static void VPrint(const char *format, va_list args)
bool IsEmpty() const
Definition: data-flow.h:164
HGraph * graph() const
Definition: hydrogen.h:2802
void UpdateControlFlowRange(Token::Value op, HValue *value, HValue *other)
void AddRange(HValue *value, Range *range)
void InferControlFlowRange(HCompareNumericAndBranch *test, HBasicBlock *dest)
static HValue * cast(HValue *value)
void AddNewRange(Range *r, Zone *zone)
const char * Mnemonic() const
Representation representation() const
void ComputeInitialRange(Zone *zone)
void Add(const T &element, AllocationPolicy allocator=AllocationPolicy())
Definition: list-inl.h:17
T & at(int i) const
Definition: list.h:69
Pending(HBasicBlock *block, int last_changed_range)
HBasicBlock * block() const
bool Equals(const Representation &other) const
static const char * Name(Value tok)
Definition: token.h:180
static Value NegateCompareOp(Value op)
Definition: token.h:223
static Value ReverseCompareOp(Value op)
Definition: token.h:240
enable harmony numeric enable harmony object literal extensions Optimize object Array DOM strings and string trace pretenuring decisions of HAllocate instructions Enables optimizations which favor memory size over execution speed maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining trace the tracking of allocation sites deoptimize every n garbage collections perform array bounds checks elimination analyze liveness of environment slots and zap dead values flushes the cache of optimized code for closures on every GC allow uint32 values on optimize frames if they are used only in safe operations track concurrent recompilation artificial compilation delay in ms do not emit check maps for constant values that have a leaf deoptimize the optimized code if the layout of the maps changes enable context specialization in TurboFan execution budget before interrupt is triggered max percentage of megamorphic generic ICs to allow optimization enable use of SAHF instruction if enable use of VFP3 instructions if available enable use of NEON instructions if enable use of SDIV and UDIV instructions if enable use of MLS instructions if enable loading bit constant by means of movw movt instruction enable unaligned accesses for enable use of d16 d31 registers on ARM this requires VFP3 force all emitted branches to be in long enable alignment of csp to bytes on platforms which prefer the register to always be NULL
#define DCHECK(condition)
Definition: logging.h:205
Debugger support for the V8 JavaScript engine.
Definition: accessors.cc:20