• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
7 namespace v8 {
8 namespace internal {
9 
InsertRepresentationChangeForUse(HValue * value,HValue * use_value,int use_index,Representation to)10 void 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   bool is_truncating_to_number =
28       use_value->CheckFlag(HValue::kTruncatingToNumber);
29   if (value->IsConstant()) {
30     HConstant* constant = HConstant::cast(value);
31     // Try to create a new copy of the constant with the new representation.
32     if (is_truncating_to_int && to.IsInteger32()) {
33       Maybe<HConstant*> res = constant->CopyToTruncatedInt32(graph()->zone());
34       if (res.IsJust()) new_value = res.FromJust();
35     } else {
36       new_value = constant->CopyToRepresentation(to, graph()->zone());
37     }
38   }
39 
40   if (new_value == NULL) {
41     new_value = new (graph()->zone())
42         HChange(value, to, is_truncating_to_smi, is_truncating_to_int,
43                 is_truncating_to_number);
44   }
45 
46   new_value->InsertBefore(next);
47   use_value->SetOperandAt(use_index, new_value);
48 }
49 
50 
IsNonDeoptingIntToSmiChange(HChange * change)51 static bool IsNonDeoptingIntToSmiChange(HChange* change) {
52   Representation from_rep = change->from();
53   Representation to_rep = change->to();
54   // Flags indicating Uint32 operations are set in a later Hydrogen phase.
55   DCHECK(!change->CheckFlag(HValue::kUint32));
56   return from_rep.IsInteger32() && to_rep.IsSmi() && SmiValuesAre32Bits();
57 }
58 
59 
InsertRepresentationChangesForValue(HValue * value)60 void HRepresentationChangesPhase::InsertRepresentationChangesForValue(
61     HValue* value) {
62   Representation r = value->representation();
63   if (r.IsNone()) {
64 #ifdef DEBUG
65     for (HUseIterator it(value->uses()); !it.Done(); it.Advance()) {
66       HValue* use_value = it.value();
67       int use_index = it.index();
68       Representation req = use_value->RequiredInputRepresentation(use_index);
69       DCHECK(req.IsNone());
70     }
71 #endif
72     return;
73   }
74   if (value->HasNoUses()) {
75     if (value->IsForceRepresentation()) value->DeleteAndReplaceWith(NULL);
76     return;
77   }
78 
79   for (HUseIterator it(value->uses()); !it.Done(); it.Advance()) {
80     HValue* use_value = it.value();
81     int use_index = it.index();
82     Representation req = use_value->RequiredInputRepresentation(use_index);
83     if (req.IsNone() || req.Equals(r)) continue;
84 
85     // If this is an HForceRepresentation instruction, and an HChange has been
86     // inserted above it, examine the input representation of the HChange. If
87     // that's int32, and this HForceRepresentation use is int32, and int32 to
88     // smi changes can't cause deoptimisation, set the input of the use to the
89     // input of the HChange.
90     if (value->IsForceRepresentation()) {
91       HValue* input = HForceRepresentation::cast(value)->value();
92       if (input->IsChange()) {
93         HChange* change = HChange::cast(input);
94         if (change->from().Equals(req) && IsNonDeoptingIntToSmiChange(change)) {
95           use_value->SetOperandAt(use_index, change->value());
96           continue;
97         }
98       }
99     }
100     InsertRepresentationChangeForUse(value, use_value, use_index, req);
101   }
102   if (value->HasNoUses()) {
103     DCHECK(value->IsConstant() || value->IsForceRepresentation());
104     value->DeleteAndReplaceWith(NULL);
105   } else {
106     // The only purpose of a HForceRepresentation is to represent the value
107     // after the (possible) HChange instruction.  We make it disappear.
108     if (value->IsForceRepresentation()) {
109       value->DeleteAndReplaceWith(HForceRepresentation::cast(value)->value());
110     }
111   }
112 }
113 
114 
Run()115 void HRepresentationChangesPhase::Run() {
116   // Compute truncation flag for phis:
117   //
118   // - Initially assume that all phis allow truncation to number and iteratively
119   //   remove the ones that are used in an operation that not do an implicit
120   //   ToNumber conversion.
121   // - Also assume that all Integer32 phis allow ToInt32 truncation and all
122   //   Smi phis allow truncation to Smi.
123   //
124   ZoneList<HPhi*> number_worklist(8, zone());
125   ZoneList<HPhi*> int_worklist(8, zone());
126   ZoneList<HPhi*> smi_worklist(8, zone());
127 
128   const ZoneList<HPhi*>* phi_list(graph()->phi_list());
129   for (int i = 0; i < phi_list->length(); i++) {
130     HPhi* phi = phi_list->at(i);
131     if (phi->representation().IsInteger32()) {
132       phi->SetFlag(HValue::kTruncatingToInt32);
133     } else if (phi->representation().IsSmi()) {
134       phi->SetFlag(HValue::kTruncatingToSmi);
135       phi->SetFlag(HValue::kTruncatingToInt32);
136     }
137     phi->SetFlag(HValue::kTruncatingToNumber);
138   }
139 
140   for (int i = 0; i < phi_list->length(); i++) {
141     HPhi* phi = phi_list->at(i);
142     HValue* value = NULL;
143 
144     if (phi->CheckFlag(HValue::kTruncatingToNumber) &&
145         !phi->CheckUsesForFlag(HValue::kTruncatingToNumber, &value)) {
146       number_worklist.Add(phi, zone());
147       phi->ClearFlag(HValue::kTruncatingToNumber);
148       phi->ClearFlag(HValue::kTruncatingToInt32);
149       phi->ClearFlag(HValue::kTruncatingToSmi);
150       if (FLAG_trace_representation) {
151         PrintF("#%d Phi is not truncating Number because of #%d %s\n",
152                phi->id(), value->id(), value->Mnemonic());
153       }
154     } else if (phi->representation().IsSmiOrInteger32() &&
155                !phi->CheckUsesForFlag(HValue::kTruncatingToInt32, &value)) {
156       int_worklist.Add(phi, zone());
157       phi->ClearFlag(HValue::kTruncatingToInt32);
158       phi->ClearFlag(HValue::kTruncatingToSmi);
159       if (FLAG_trace_representation) {
160         PrintF("#%d Phi is not truncating Int32 because of #%d %s\n",
161                phi->id(), value->id(), value->Mnemonic());
162       }
163     } else if (phi->representation().IsSmi() &&
164                !phi->CheckUsesForFlag(HValue::kTruncatingToSmi, &value)) {
165       smi_worklist.Add(phi, zone());
166       phi->ClearFlag(HValue::kTruncatingToSmi);
167       if (FLAG_trace_representation) {
168         PrintF("#%d Phi is not truncating Smi because of #%d %s\n",
169                phi->id(), value->id(), value->Mnemonic());
170       }
171     }
172   }
173 
174   while (!number_worklist.is_empty()) {
175     HPhi* current = number_worklist.RemoveLast();
176     for (int i = current->OperandCount() - 1; i >= 0; --i) {
177       HValue* input = current->OperandAt(i);
178       if (input->IsPhi() && input->CheckFlag(HValue::kTruncatingToNumber)) {
179         if (FLAG_trace_representation) {
180           PrintF("#%d Phi is not truncating Number because of #%d %s\n",
181                  input->id(), current->id(), current->Mnemonic());
182         }
183         input->ClearFlag(HValue::kTruncatingToNumber);
184         input->ClearFlag(HValue::kTruncatingToInt32);
185         input->ClearFlag(HValue::kTruncatingToSmi);
186         number_worklist.Add(HPhi::cast(input), zone());
187       }
188     }
189   }
190 
191   while (!int_worklist.is_empty()) {
192     HPhi* current = int_worklist.RemoveLast();
193     for (int i = 0; i < current->OperandCount(); ++i) {
194       HValue* input = current->OperandAt(i);
195       if (input->IsPhi() &&
196           input->representation().IsSmiOrInteger32() &&
197           input->CheckFlag(HValue::kTruncatingToInt32)) {
198         if (FLAG_trace_representation) {
199           PrintF("#%d Phi is not truncating Int32 because of #%d %s\n",
200                  input->id(), current->id(), current->Mnemonic());
201         }
202         input->ClearFlag(HValue::kTruncatingToInt32);
203         int_worklist.Add(HPhi::cast(input), zone());
204       }
205     }
206   }
207 
208   while (!smi_worklist.is_empty()) {
209     HPhi* current = smi_worklist.RemoveLast();
210     for (int i = 0; i < current->OperandCount(); ++i) {
211       HValue* input = current->OperandAt(i);
212       if (input->IsPhi() &&
213           input->representation().IsSmi() &&
214           input->CheckFlag(HValue::kTruncatingToSmi)) {
215         if (FLAG_trace_representation) {
216           PrintF("#%d Phi is not truncating Smi because of #%d %s\n",
217                  input->id(), current->id(), current->Mnemonic());
218         }
219         input->ClearFlag(HValue::kTruncatingToSmi);
220         smi_worklist.Add(HPhi::cast(input), zone());
221       }
222     }
223   }
224 
225   const ZoneList<HBasicBlock*>* blocks(graph()->blocks());
226   for (int i = 0; i < blocks->length(); ++i) {
227     // Process phi instructions first.
228     const HBasicBlock* block(blocks->at(i));
229     const ZoneList<HPhi*>* phis = block->phis();
230     for (int j = 0; j < phis->length(); j++) {
231       InsertRepresentationChangesForValue(phis->at(j));
232     }
233 
234     // Process normal instructions.
235     for (HInstruction* current = block->first(); current != NULL; ) {
236       HInstruction* next = current->next();
237       InsertRepresentationChangesForValue(current);
238       current = next;
239     }
240   }
241 }
242 
243 }  // namespace internal
244 }  // namespace v8
245