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/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.has_value) new_value = res.value; 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()) return; 67 if (value->HasNoUses()) { 68 if (value->IsForceRepresentation()) value->DeleteAndReplaceWith(NULL); 69 return; 70 } 71 72 for (HUseIterator it(value->uses()); !it.Done(); it.Advance()) { 73 HValue* use_value = it.value(); 74 int use_index = it.index(); 75 Representation req = use_value->RequiredInputRepresentation(use_index); 76 if (req.IsNone() || req.Equals(r)) continue; 77 78 // If this is an HForceRepresentation instruction, and an HChange has been 79 // inserted above it, examine the input representation of the HChange. If 80 // that's int32, and this HForceRepresentation use is int32, and int32 to 81 // smi changes can't cause deoptimisation, set the input of the use to the 82 // input of the HChange. 83 if (value->IsForceRepresentation()) { 84 HValue* input = HForceRepresentation::cast(value)->value(); 85 if (input->IsChange()) { 86 HChange* change = HChange::cast(input); 87 if (change->from().Equals(req) && IsNonDeoptingIntToSmiChange(change)) { 88 use_value->SetOperandAt(use_index, change->value()); 89 continue; 90 } 91 } 92 } 93 InsertRepresentationChangeForUse(value, use_value, use_index, req); 94 } 95 if (value->HasNoUses()) { 96 DCHECK(value->IsConstant() || value->IsForceRepresentation()); 97 value->DeleteAndReplaceWith(NULL); 98 } else { 99 // The only purpose of a HForceRepresentation is to represent the value 100 // after the (possible) HChange instruction. We make it disappear. 101 if (value->IsForceRepresentation()) { 102 value->DeleteAndReplaceWith(HForceRepresentation::cast(value)->value()); 103 } 104 } 105 } 106 107 108 void HRepresentationChangesPhase::Run() { 109 // Compute truncation flag for phis: Initially assume that all 110 // int32-phis allow truncation and iteratively remove the ones that 111 // are used in an operation that does not allow a truncating 112 // conversion. 113 ZoneList<HPhi*> int_worklist(8, zone()); 114 ZoneList<HPhi*> smi_worklist(8, zone()); 115 116 const ZoneList<HPhi*>* phi_list(graph()->phi_list()); 117 for (int i = 0; i < phi_list->length(); i++) { 118 HPhi* phi = phi_list->at(i); 119 if (phi->representation().IsInteger32()) { 120 phi->SetFlag(HValue::kTruncatingToInt32); 121 } else if (phi->representation().IsSmi()) { 122 phi->SetFlag(HValue::kTruncatingToSmi); 123 phi->SetFlag(HValue::kTruncatingToInt32); 124 } 125 } 126 127 for (int i = 0; i < phi_list->length(); i++) { 128 HPhi* phi = phi_list->at(i); 129 HValue* value = NULL; 130 if (phi->representation().IsSmiOrInteger32() && 131 !phi->CheckUsesForFlag(HValue::kTruncatingToInt32, &value)) { 132 int_worklist.Add(phi, zone()); 133 phi->ClearFlag(HValue::kTruncatingToInt32); 134 if (FLAG_trace_representation) { 135 PrintF("#%d Phi is not truncating Int32 because of #%d %s\n", 136 phi->id(), value->id(), value->Mnemonic()); 137 } 138 } 139 140 if (phi->representation().IsSmi() && 141 !phi->CheckUsesForFlag(HValue::kTruncatingToSmi, &value)) { 142 smi_worklist.Add(phi, zone()); 143 phi->ClearFlag(HValue::kTruncatingToSmi); 144 if (FLAG_trace_representation) { 145 PrintF("#%d Phi is not truncating Smi because of #%d %s\n", 146 phi->id(), value->id(), value->Mnemonic()); 147 } 148 } 149 } 150 151 while (!int_worklist.is_empty()) { 152 HPhi* current = int_worklist.RemoveLast(); 153 for (int i = 0; i < current->OperandCount(); ++i) { 154 HValue* input = current->OperandAt(i); 155 if (input->IsPhi() && 156 input->representation().IsSmiOrInteger32() && 157 input->CheckFlag(HValue::kTruncatingToInt32)) { 158 if (FLAG_trace_representation) { 159 PrintF("#%d Phi is not truncating Int32 because of #%d %s\n", 160 input->id(), current->id(), current->Mnemonic()); 161 } 162 input->ClearFlag(HValue::kTruncatingToInt32); 163 int_worklist.Add(HPhi::cast(input), zone()); 164 } 165 } 166 } 167 168 while (!smi_worklist.is_empty()) { 169 HPhi* current = smi_worklist.RemoveLast(); 170 for (int i = 0; i < current->OperandCount(); ++i) { 171 HValue* input = current->OperandAt(i); 172 if (input->IsPhi() && 173 input->representation().IsSmi() && 174 input->CheckFlag(HValue::kTruncatingToSmi)) { 175 if (FLAG_trace_representation) { 176 PrintF("#%d Phi is not truncating Smi because of #%d %s\n", 177 input->id(), current->id(), current->Mnemonic()); 178 } 179 input->ClearFlag(HValue::kTruncatingToSmi); 180 smi_worklist.Add(HPhi::cast(input), zone()); 181 } 182 } 183 } 184 185 const ZoneList<HBasicBlock*>* blocks(graph()->blocks()); 186 for (int i = 0; i < blocks->length(); ++i) { 187 // Process phi instructions first. 188 const HBasicBlock* block(blocks->at(i)); 189 const ZoneList<HPhi*>* phis = block->phis(); 190 for (int j = 0; j < phis->length(); j++) { 191 InsertRepresentationChangesForValue(phis->at(j)); 192 } 193 194 // Process normal instructions. 195 for (HInstruction* current = block->first(); current != NULL; ) { 196 HInstruction* next = current->next(); 197 InsertRepresentationChangesForValue(current); 198 current = next; 199 } 200 } 201 } 202 203 } } // namespace v8::internal 204