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 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 54 static 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 63 void 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 118 void 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