Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame^] | 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 |