hydrogen-representation-changes.cc 7.77 KB
Newer Older
1
// Copyright 2013 the V8 project authors. All rights reserved.
2 3
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
4

5
#include "src/hydrogen-representation-changes.h"
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24

namespace v8 {
namespace internal {

void HRepresentationChangesPhase::InsertRepresentationChangeForUse(
    HValue* value, HValue* use_value, int use_index, Representation to) {
  // Insert the representation change right before its use. For phi-uses we
  // insert at the end of the corresponding predecessor.
  HInstruction* next = NULL;
  if (use_value->IsPhi()) {
    next = use_value->block()->predecessors()->at(use_index)->end();
  } else {
    next = HInstruction::cast(use_value);
  }
  // For constants we try to make the representation change at compile
  // time. When a representation change is not possible without loss of
  // information we treat constants like normal instructions and insert the
  // change instructions for them.
  HInstruction* new_value = NULL;
25 26
  bool is_truncating_to_smi = use_value->CheckFlag(HValue::kTruncatingToSmi);
  bool is_truncating_to_int = use_value->CheckFlag(HValue::kTruncatingToInt32);
27 28 29
  if (value->IsConstant()) {
    HConstant* constant = HConstant::cast(value);
    // Try to create a new copy of the constant with the new representation.
30
    if (is_truncating_to_int && to.IsInteger32()) {
31 32 33 34 35
      Maybe<HConstant*> res = constant->CopyToTruncatedInt32(graph()->zone());
      if (res.has_value) new_value = res.value;
    } else {
      new_value = constant->CopyToRepresentation(to, graph()->zone());
    }
36 37 38
  }

  if (new_value == NULL) {
39 40
    new_value = new(graph()->zone()) HChange(
        value, to, is_truncating_to_smi, is_truncating_to_int);
41
    if (!use_value->operand_position(use_index).IsUnknown()) {
vegorov@chromium.org's avatar
vegorov@chromium.org committed
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 50 51 52 53
  }

  new_value->InsertBefore(next);
  use_value->SetOperandAt(use_index, new_value);
}


54 55 56 57
static bool IsNonDeoptingIntToSmiChange(HChange* change) {
  Representation from_rep = change->from();
  Representation to_rep = change->to();
  // Flags indicating Uint32 operations are set in a later Hydrogen phase.
58
  DCHECK(!change->CheckFlag(HValue::kUint32));
59 60 61 62
  return from_rep.IsInteger32() && to_rep.IsSmi() && SmiValuesAre32Bits();
}


63 64 65
void HRepresentationChangesPhase::InsertRepresentationChangesForValue(
    HValue* value) {
  Representation r = value->representation();
66 67 68 69 70 71 72 73 74 75 76
  if (r.IsNone()) {
#ifdef DEBUG
    for (HUseIterator it(value->uses()); !it.Done(); it.Advance()) {
      HValue* use_value = it.value();
      int use_index = it.index();
      Representation req = use_value->RequiredInputRepresentation(use_index);
      DCHECK(req.IsNone());
    }
#endif
    return;
  }
77 78 79 80
  if (value->HasNoUses()) {
    if (value->IsForceRepresentation()) value->DeleteAndReplaceWith(NULL);
    return;
  }
81 82 83 84 85 86

  for (HUseIterator it(value->uses()); !it.Done(); it.Advance()) {
    HValue* use_value = it.value();
    int use_index = it.index();
    Representation req = use_value->RequiredInputRepresentation(use_index);
    if (req.IsNone() || req.Equals(r)) continue;
87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102

    // If this is an HForceRepresentation instruction, and an HChange has been
    // inserted above it, examine the input representation of the HChange. If
    // that's int32, and this HForceRepresentation use is int32, and int32 to
    // smi changes can't cause deoptimisation, set the input of the use to the
    // input of the HChange.
    if (value->IsForceRepresentation()) {
      HValue* input = HForceRepresentation::cast(value)->value();
      if (input->IsChange()) {
        HChange* change = HChange::cast(input);
        if (change->from().Equals(req) && IsNonDeoptingIntToSmiChange(change)) {
          use_value->SetOperandAt(use_index, change->value());
          continue;
        }
      }
    }
103 104 105
    InsertRepresentationChangeForUse(value, use_value, use_index, req);
  }
  if (value->HasNoUses()) {
106
    DCHECK(value->IsConstant() || value->IsForceRepresentation());
107
    value->DeleteAndReplaceWith(NULL);
108 109 110 111 112 113
  } else {
    // The only purpose of a HForceRepresentation is to represent the value
    // after the (possible) HChange instruction.  We make it disappear.
    if (value->IsForceRepresentation()) {
      value->DeleteAndReplaceWith(HForceRepresentation::cast(value)->value());
    }
114 115 116 117 118 119 120 121 122
  }
}


void HRepresentationChangesPhase::Run() {
  // Compute truncation flag for phis: Initially assume that all
  // int32-phis allow truncation and iteratively remove the ones that
  // are used in an operation that does not allow a truncating
  // conversion.
123 124
  ZoneList<HPhi*> int_worklist(8, zone());
  ZoneList<HPhi*> smi_worklist(8, zone());
125 126 127 128 129 130

  const ZoneList<HPhi*>* phi_list(graph()->phi_list());
  for (int i = 0; i < phi_list->length(); i++) {
    HPhi* phi = phi_list->at(i);
    if (phi->representation().IsInteger32()) {
      phi->SetFlag(HValue::kTruncatingToInt32);
131 132
    } else if (phi->representation().IsSmi()) {
      phi->SetFlag(HValue::kTruncatingToSmi);
133
      phi->SetFlag(HValue::kTruncatingToInt32);
134 135 136 137 138
    }
  }

  for (int i = 0; i < phi_list->length(); i++) {
    HPhi* phi = phi_list->at(i);
139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167
    HValue* value = NULL;
    if (phi->representation().IsSmiOrInteger32() &&
        !phi->CheckUsesForFlag(HValue::kTruncatingToInt32, &value)) {
      int_worklist.Add(phi, zone());
      phi->ClearFlag(HValue::kTruncatingToInt32);
      if (FLAG_trace_representation) {
        PrintF("#%d Phi is not truncating Int32 because of #%d %s\n",
               phi->id(), value->id(), value->Mnemonic());
      }
    }

    if (phi->representation().IsSmi() &&
        !phi->CheckUsesForFlag(HValue::kTruncatingToSmi, &value)) {
      smi_worklist.Add(phi, zone());
      phi->ClearFlag(HValue::kTruncatingToSmi);
      if (FLAG_trace_representation) {
        PrintF("#%d Phi is not truncating Smi because of #%d %s\n",
               phi->id(), value->id(), value->Mnemonic());
      }
    }
  }

  while (!int_worklist.is_empty()) {
    HPhi* current = int_worklist.RemoveLast();
    for (int i = 0; i < current->OperandCount(); ++i) {
      HValue* input = current->OperandAt(i);
      if (input->IsPhi() &&
          input->representation().IsSmiOrInteger32() &&
          input->CheckFlag(HValue::kTruncatingToInt32)) {
168
        if (FLAG_trace_representation) {
169 170
          PrintF("#%d Phi is not truncating Int32 because of #%d %s\n",
                 input->id(), current->id(), current->Mnemonic());
171
        }
172 173
        input->ClearFlag(HValue::kTruncatingToInt32);
        int_worklist.Add(HPhi::cast(input), zone());
174 175 176 177
      }
    }
  }

178 179
  while (!smi_worklist.is_empty()) {
    HPhi* current = smi_worklist.RemoveLast();
180 181 182
    for (int i = 0; i < current->OperandCount(); ++i) {
      HValue* input = current->OperandAt(i);
      if (input->IsPhi() &&
183 184
          input->representation().IsSmi() &&
          input->CheckFlag(HValue::kTruncatingToSmi)) {
185
        if (FLAG_trace_representation) {
186
          PrintF("#%d Phi is not truncating Smi because of #%d %s\n",
187 188
                 input->id(), current->id(), current->Mnemonic());
        }
189
        input->ClearFlag(HValue::kTruncatingToSmi);
190
        smi_worklist.Add(HPhi::cast(input), zone());
191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213
      }
    }
  }

  const ZoneList<HBasicBlock*>* blocks(graph()->blocks());
  for (int i = 0; i < blocks->length(); ++i) {
    // Process phi instructions first.
    const HBasicBlock* block(blocks->at(i));
    const ZoneList<HPhi*>* phis = block->phis();
    for (int j = 0; j < phis->length(); j++) {
      InsertRepresentationChangesForValue(phis->at(j));
    }

    // Process normal instructions.
    for (HInstruction* current = block->first(); current != NULL; ) {
      HInstruction* next = current->next();
      InsertRepresentationChangesForValue(current);
      current = next;
    }
  }
}

} }  // namespace v8::internal