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
5#include "src/crankshaft/hydrogen-representation-changes.h"
6
7namespace v8 {
8namespace internal {
9
10void HRepresentationChangesPhase::InsertRepresentationChangeForUse(
11    HValue* value, HValue* use_value, int use_index, Representation to) {
12  // Insert the representation change right before its use. For phi-uses we
13  // insert at the end of the corresponding predecessor.
14  HInstruction* next = NULL;
15  if (use_value->IsPhi()) {
16    next = use_value->block()->predecessors()->at(use_index)->end();
17  } else {
18    next = HInstruction::cast(use_value);
19  }
20  // For constants we try to make the representation change at compile
21  // time. When a representation change is not possible without loss of
22  // information we treat constants like normal instructions and insert the
23  // change instructions for them.
24  HInstruction* new_value = NULL;
25  bool is_truncating_to_smi = use_value->CheckFlag(HValue::kTruncatingToSmi);
26  bool is_truncating_to_int = use_value->CheckFlag(HValue::kTruncatingToInt32);
27  if (value->IsConstant()) {
28    HConstant* constant = HConstant::cast(value);
29    // Try to create a new copy of the constant with the new representation.
30    if (is_truncating_to_int && to.IsInteger32()) {
31      Maybe<HConstant*> res = constant->CopyToTruncatedInt32(graph()->zone());
32      if (res.IsJust()) new_value = res.FromJust();
33    } else {
34      new_value = constant->CopyToRepresentation(to, graph()->zone());
35    }
36  }
37
38  if (new_value == NULL) {
39    new_value = new(graph()->zone()) HChange(
40        value, to, is_truncating_to_smi, is_truncating_to_int);
41    if (!use_value->operand_position(use_index).IsUnknown()) {
42      new_value->set_position(use_value->operand_position(use_index));
43    } else {
44      DCHECK(!FLAG_hydrogen_track_positions ||
45             !graph()->info()->IsOptimizing());
46    }
47  }
48
49  new_value->InsertBefore(next);
50  use_value->SetOperandAt(use_index, new_value);
51}
52
53
54static bool IsNonDeoptingIntToSmiChange(HChange* change) {
55  Representation from_rep = change->from();
56  Representation to_rep = change->to();
57  // Flags indicating Uint32 operations are set in a later Hydrogen phase.
58  DCHECK(!change->CheckFlag(HValue::kUint32));
59  return from_rep.IsInteger32() && to_rep.IsSmi() && SmiValuesAre32Bits();
60}
61
62
63void HRepresentationChangesPhase::InsertRepresentationChangesForValue(
64    HValue* value) {
65  Representation r = value->representation();
66  if (r.IsNone()) {
67#ifdef DEBUG
68    for (HUseIterator it(value->uses()); !it.Done(); it.Advance()) {
69      HValue* use_value = it.value();
70      int use_index = it.index();
71      Representation req = use_value->RequiredInputRepresentation(use_index);
72      DCHECK(req.IsNone());
73    }
74#endif
75    return;
76  }
77  if (value->HasNoUses()) {
78    if (value->IsForceRepresentation()) value->DeleteAndReplaceWith(NULL);
79    return;
80  }
81
82  for (HUseIterator it(value->uses()); !it.Done(); it.Advance()) {
83    HValue* use_value = it.value();
84    int use_index = it.index();
85    Representation req = use_value->RequiredInputRepresentation(use_index);
86    if (req.IsNone() || req.Equals(r)) continue;
87
88    // If this is an HForceRepresentation instruction, and an HChange has been
89    // inserted above it, examine the input representation of the HChange. If
90    // that's int32, and this HForceRepresentation use is int32, and int32 to
91    // smi changes can't cause deoptimisation, set the input of the use to the
92    // input of the HChange.
93    if (value->IsForceRepresentation()) {
94      HValue* input = HForceRepresentation::cast(value)->value();
95      if (input->IsChange()) {
96        HChange* change = HChange::cast(input);
97        if (change->from().Equals(req) && IsNonDeoptingIntToSmiChange(change)) {
98          use_value->SetOperandAt(use_index, change->value());
99          continue;
100        }
101      }
102    }
103    InsertRepresentationChangeForUse(value, use_value, use_index, req);
104  }
105  if (value->HasNoUses()) {
106    DCHECK(value->IsConstant() || value->IsForceRepresentation());
107    value->DeleteAndReplaceWith(NULL);
108  } else {
109    // The only purpose of a HForceRepresentation is to represent the value
110    // after the (possible) HChange instruction.  We make it disappear.
111    if (value->IsForceRepresentation()) {
112      value->DeleteAndReplaceWith(HForceRepresentation::cast(value)->value());
113    }
114  }
115}
116
117
118void HRepresentationChangesPhase::Run() {
119  // Compute truncation flag for phis: Initially assume that all
120  // int32-phis allow truncation and iteratively remove the ones that
121  // are used in an operation that does not allow a truncating
122  // conversion.
123  ZoneList<HPhi*> int_worklist(8, zone());
124  ZoneList<HPhi*> smi_worklist(8, zone());
125
126  const ZoneList<HPhi*>* phi_list(graph()->phi_list());
127  for (int i = 0; i < phi_list->length(); i++) {
128    HPhi* phi = phi_list->at(i);
129    if (phi->representation().IsInteger32()) {
130      phi->SetFlag(HValue::kTruncatingToInt32);
131    } else if (phi->representation().IsSmi()) {
132      phi->SetFlag(HValue::kTruncatingToSmi);
133      phi->SetFlag(HValue::kTruncatingToInt32);
134    }
135  }
136
137  for (int i = 0; i < phi_list->length(); i++) {
138    HPhi* phi = phi_list->at(i);
139    HValue* value = NULL;
140    if (phi->representation().IsSmiOrInteger32() &&
141        !phi->CheckUsesForFlag(HValue::kTruncatingToInt32, &value)) {
142      int_worklist.Add(phi, zone());
143      phi->ClearFlag(HValue::kTruncatingToInt32);
144      if (FLAG_trace_representation) {
145        PrintF("#%d Phi is not truncating Int32 because of #%d %s\n",
146               phi->id(), value->id(), value->Mnemonic());
147      }
148    }
149
150    if (phi->representation().IsSmi() &&
151        !phi->CheckUsesForFlag(HValue::kTruncatingToSmi, &value)) {
152      smi_worklist.Add(phi, zone());
153      phi->ClearFlag(HValue::kTruncatingToSmi);
154      if (FLAG_trace_representation) {
155        PrintF("#%d Phi is not truncating Smi because of #%d %s\n",
156               phi->id(), value->id(), value->Mnemonic());
157      }
158    }
159  }
160
161  while (!int_worklist.is_empty()) {
162    HPhi* current = int_worklist.RemoveLast();
163    for (int i = 0; i < current->OperandCount(); ++i) {
164      HValue* input = current->OperandAt(i);
165      if (input->IsPhi() &&
166          input->representation().IsSmiOrInteger32() &&
167          input->CheckFlag(HValue::kTruncatingToInt32)) {
168        if (FLAG_trace_representation) {
169          PrintF("#%d Phi is not truncating Int32 because of #%d %s\n",
170                 input->id(), current->id(), current->Mnemonic());
171        }
172        input->ClearFlag(HValue::kTruncatingToInt32);
173        int_worklist.Add(HPhi::cast(input), zone());
174      }
175    }
176  }
177
178  while (!smi_worklist.is_empty()) {
179    HPhi* current = smi_worklist.RemoveLast();
180    for (int i = 0; i < current->OperandCount(); ++i) {
181      HValue* input = current->OperandAt(i);
182      if (input->IsPhi() &&
183          input->representation().IsSmi() &&
184          input->CheckFlag(HValue::kTruncatingToSmi)) {
185        if (FLAG_trace_representation) {
186          PrintF("#%d Phi is not truncating Smi because of #%d %s\n",
187                 input->id(), current->id(), current->Mnemonic());
188        }
189        input->ClearFlag(HValue::kTruncatingToSmi);
190        smi_worklist.Add(HPhi::cast(input), zone());
191      }
192    }
193  }
194
195  const ZoneList<HBasicBlock*>* blocks(graph()->blocks());
196  for (int i = 0; i < blocks->length(); ++i) {
197    // Process phi instructions first.
198    const HBasicBlock* block(blocks->at(i));
199    const ZoneList<HPhi*>* phis = block->phis();
200    for (int j = 0; j < phis->length(); j++) {
201      InsertRepresentationChangesForValue(phis->at(j));
202    }
203
204    // Process normal instructions.
205    for (HInstruction* current = block->first(); current != NULL; ) {
206      HInstruction* next = current->next();
207      InsertRepresentationChangesForValue(current);
208      current = next;
209    }
210  }
211}
212
213}  // namespace internal
214}  // namespace v8
215