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