// Copyright 2013 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "src/crankshaft/hydrogen-uint32-analysis.h"

namespace v8 {
namespace internal {


static bool IsUnsignedLoad(HLoadKeyed* instr) {
  switch (instr->elements_kind()) {
    case UINT8_ELEMENTS:
    case UINT16_ELEMENTS:
    case UINT32_ELEMENTS:
    case UINT8_CLAMPED_ELEMENTS:
      return true;
    default:
      return false;
  }
}


static bool IsUint32Operation(HValue* instr) {
  return instr->IsShr() ||
      (instr->IsLoadKeyed() && IsUnsignedLoad(HLoadKeyed::cast(instr))) ||
      (instr->IsInteger32Constant() && instr->GetInteger32Constant() >= 0);
}


bool HUint32AnalysisPhase::IsSafeUint32Use(HValue* val, HValue* use) {
  // Operations that operate on bits are safe.
  if (use->IsBitwise() || use->IsShl() || use->IsSar() || use->IsShr()) {
    return true;
  } else if (use->IsSimulate() || use->IsArgumentsObject()) {
    // Deoptimization has special support for uint32.
    return true;
  } else if (use->IsChange()) {
    // Conversions have special support for uint32.
    // This DCHECK guards that the conversion in question is actually
    // implemented. Do not extend the whitelist without adding
    // support to LChunkBuilder::DoChange().
    DCHECK(HChange::cast(use)->to().IsDouble() ||
           HChange::cast(use)->to().IsSmi() ||
           HChange::cast(use)->to().IsTagged());
    return true;
  } else if (use->IsStoreKeyed()) {
    HStoreKeyed* store = HStoreKeyed::cast(use);
    if (store->is_fixed_typed_array()) {
      // Storing a value into an external integer array is a bit level
      // operation.
      if (store->value() == val) {
        // Clamping or a conversion to double should have beed inserted.
        DCHECK(store->elements_kind() != UINT8_CLAMPED_ELEMENTS);
        DCHECK(store->elements_kind() != FLOAT32_ELEMENTS);
        DCHECK(store->elements_kind() != FLOAT64_ELEMENTS);
        return true;
      }
    }
  } else if (use->IsCompareNumericAndBranch()) {
    HCompareNumericAndBranch* c = HCompareNumericAndBranch::cast(use);
    return IsUint32Operation(c->left()) && IsUint32Operation(c->right());
  }

  return false;
}


// Iterate over all uses and verify that they are uint32 safe: either don't
// distinguish between int32 and uint32 due to their bitwise nature or
// have special support for uint32 values.
// Encountered phis are optimistically treated as safe uint32 uses,
// marked with kUint32 flag and collected in the phis_ list. A separate
// pass will be performed later by UnmarkUnsafePhis to clear kUint32 from
// phis that are not actually uint32-safe (it requires fix point iteration).
bool HUint32AnalysisPhase::Uint32UsesAreSafe(HValue* uint32val) {
  bool collect_phi_uses = false;
  for (HUseIterator it(uint32val->uses()); !it.Done(); it.Advance()) {
    HValue* use = it.value();

    if (use->IsPhi()) {
      if (!use->CheckFlag(HInstruction::kUint32)) {
        // There is a phi use of this value from a phi that is not yet
        // collected in phis_ array. Separate pass is required.
        collect_phi_uses = true;
      }

      // Optimistically treat phis as uint32 safe.
      continue;
    }

    if (!IsSafeUint32Use(uint32val, use)) {
      return false;
    }
  }

  if (collect_phi_uses) {
    for (HUseIterator it(uint32val->uses()); !it.Done(); it.Advance()) {
      HValue* use = it.value();

      // There is a phi use of this value from a phi that is not yet
      // collected in phis_ array. Separate pass is required.
      if (use->IsPhi() && !use->CheckFlag(HInstruction::kUint32)) {
        use->SetFlag(HInstruction::kUint32);
        phis_.Add(HPhi::cast(use), zone());
      }
    }
  }

  return true;
}


// Check if all operands to the given phi are marked with kUint32 flag.
bool HUint32AnalysisPhase::CheckPhiOperands(HPhi* phi) {
  if (!phi->CheckFlag(HInstruction::kUint32)) {
    // This phi is not uint32 safe. No need to check operands.
    return false;
  }

  for (int j = 0; j < phi->OperandCount(); j++) {
    HValue* operand = phi->OperandAt(j);
    if (!operand->CheckFlag(HInstruction::kUint32)) {
      // Lazily mark constants that fit into uint32 range with kUint32 flag.
      if (operand->IsInteger32Constant() &&
          operand->GetInteger32Constant() >= 0) {
        operand->SetFlag(HInstruction::kUint32);
        continue;
      }

      // This phi is not safe, some operands are not uint32 values.
      return false;
    }
  }

  return true;
}


// Remove kUint32 flag from the phi itself and its operands. If any operand
// was a phi marked with kUint32 place it into a worklist for
// transitive clearing of kUint32 flag.
void HUint32AnalysisPhase::UnmarkPhi(HPhi* phi, ZoneList<HPhi*>* worklist) {
  phi->ClearFlag(HInstruction::kUint32);
  for (int j = 0; j < phi->OperandCount(); j++) {
    HValue* operand = phi->OperandAt(j);
    if (operand->CheckFlag(HInstruction::kUint32)) {
      operand->ClearFlag(HInstruction::kUint32);
      if (operand->IsPhi()) {
        worklist->Add(HPhi::cast(operand), zone());
      }
    }
  }
}


void HUint32AnalysisPhase::UnmarkUnsafePhis() {
  // No phis were collected. Nothing to do.
  if (phis_.length() == 0) return;

  // Worklist used to transitively clear kUint32 from phis that
  // are used as arguments to other phis.
  ZoneList<HPhi*> worklist(phis_.length(), zone());

  // Phi can be used as a uint32 value if and only if
  // all its operands are uint32 values and all its
  // uses are uint32 safe.

  // Iterate over collected phis and unmark those that
  // are unsafe. When unmarking phi unmark its operands
  // and add it to the worklist if it is a phi as well.
  // Phis that are still marked as safe are shifted down
  // so that all safe phis form a prefix of the phis_ array.
  int phi_count = 0;
  for (int i = 0; i < phis_.length(); i++) {
    HPhi* phi = phis_[i];

    if (CheckPhiOperands(phi) && Uint32UsesAreSafe(phi)) {
      phis_[phi_count++] = phi;
    } else {
      UnmarkPhi(phi, &worklist);
    }
  }

  // Now phis array contains only those phis that have safe
  // non-phi uses. Start transitively clearing kUint32 flag
  // from phi operands of discovered non-safe phis until
  // only safe phis are left.
  while (!worklist.is_empty())  {
    while (!worklist.is_empty()) {
      HPhi* phi = worklist.RemoveLast();
      UnmarkPhi(phi, &worklist);
    }

    // Check if any operands to safe phis were unmarked
    // turning a safe phi into unsafe. The same value
    // can flow into several phis.
    int new_phi_count = 0;
    for (int i = 0; i < phi_count; i++) {
      HPhi* phi = phis_[i];

      if (CheckPhiOperands(phi)) {
        phis_[new_phi_count++] = phi;
      } else {
        UnmarkPhi(phi, &worklist);
      }
    }
    phi_count = new_phi_count;
  }
}


void HUint32AnalysisPhase::Run() {
  if (!graph()->has_uint32_instructions()) return;

  ZoneList<HInstruction*>* uint32_instructions = graph()->uint32_instructions();
  for (int i = 0; i < uint32_instructions->length(); ++i) {
    // Analyze instruction and mark it with kUint32 if all
    // its uses are uint32 safe.
    HInstruction* current = uint32_instructions->at(i);
    if (current->IsLinked() &&
        current->representation().IsInteger32() &&
        Uint32UsesAreSafe(current)) {
      current->SetFlag(HInstruction::kUint32);
    }
  }

  // Some phis might have been optimistically marked with kUint32 flag.
  // Remove this flag from those phis that are unsafe and propagate
  // this information transitively potentially clearing kUint32 flag
  // from some non-phi operations that are used as operands to unsafe phis.
  UnmarkUnsafePhis();
}


}  // namespace internal
}  // namespace v8
