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 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 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 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 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