// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

import '../common.dart';
import '../js_backend/namer.dart' show ModularNamer;
import 'codegen.dart' show CodegenPhase;
import 'nodes.dart';

/// The [LiveRange] class covers a range where an instruction is live.
class LiveRange {
  final int start;
  // [end] is not final because it can be updated due to loops.
  int end;
  LiveRange(this.start, this.end) {
    assert(start <= end);
  }

  @override
  String toString() => '[$start $end[';
}

/// The [LiveInterval] class contains the list of ranges where an
/// instruction is live.
class LiveInterval {
  /// The id where the instruction is defined.
  int start;
  final List<LiveRange> ranges;
  LiveInterval() : ranges = <LiveRange>[];

  // We want [HCheck] instructions to have the same name as the
  // instruction it checks, so both instructions should share the same
  // live ranges.
  LiveInterval.forCheck(this.start, LiveInterval checkedInterval)
      : ranges = checkedInterval.ranges;

  /// Update all ranges that are contained in [from, to[ to
  /// die at [to].
  void loopUpdate(int from, int to) {
    for (LiveRange range in ranges) {
      if (from <= range.start && range.end < to) {
        range.end = to;
      }
    }
  }

  /// Add a new range to this interval.
  void add(LiveRange interval) {
    ranges.add(interval);
  }

  /// Returns true if one of the ranges of this interval dies at [at].
  bool diesAt(int at) {
    for (LiveRange range in ranges) {
      if (range.end == at) return true;
    }
    return false;
  }

  @override
  String toString() {
    List<String> res = <String>[];
    for (final interval in ranges) res.add(interval.toString());
    return '(${res.join(", ")})';
  }
}

/// The [LiveEnvironment] class contains the liveIn set of a basic
/// block. A liveIn set of a block contains the instructions that are
/// live when entering that block.
class LiveEnvironment {
  /// The instruction id where the basic block starts. See
  /// [SsaLiveIntervalBuilder.instructionId].
  int startId;

  /// The instruction id where the basic block ends.
  final int endId;

  /// Loop markers that will be updated once the loop header is
  /// visited. The liveIn set of the loop header will be merged into this
  /// environment. [loopMarkers] is a mapping from block header to the
  /// end instruction id of the loop exit block.
  final Map<HBasicBlock, int> loopMarkers;

  /// The instructions that are live in this basic block. The values of
  /// the map contain the instruction ids where the instructions die.
  /// It will be used when adding a range to the live interval of an
  /// instruction.
  final Map<HInstruction, int> liveInstructions;

  /// Map containing the live intervals of instructions.
  final Map<HInstruction, LiveInterval> liveIntervals;

  LiveEnvironment(this.liveIntervals, this.endId)
      : liveInstructions = new Map<HInstruction, int>(),
        loopMarkers = new Map<HBasicBlock, int>();

  /// Remove an instruction from the liveIn set. This method also
  /// updates the live interval of [instruction] to contain the new
  /// range: [id, / id contained in [liveInstructions] /].
  void remove(HInstruction instruction, int id) {
    LiveInterval interval =
        liveIntervals.putIfAbsent(instruction, () => new LiveInterval());
    int lastId = liveInstructions[instruction];
    // If [lastId] is null, then this instruction is not being used.
    interval.add(new LiveRange(id, lastId == null ? id : lastId));
    // The instruction is defined at [id].
    interval.start = id;
    liveInstructions.remove(instruction);
  }

  /// Add [instruction] to the liveIn set. If the instruction is not
  /// already in the set, we save the id where it dies.
  void add(HInstruction instruction, int userId) {
    // Note that we are visiting the graph in post-dominator order, so
    // the first time we see a variable is when it dies.
    liveInstructions.putIfAbsent(instruction, () => userId);
  }

  /// Merge this environment with [other]. Update the end id of
  /// instructions in case they are different between this and [other].
  void mergeWith(LiveEnvironment other) {
    other.liveInstructions.forEach((HInstruction instruction, int existingId) {
      // If both environments have the same instruction id of where
      // [instruction] dies, there is no need to update the live
      // interval of [instruction]. For example the if block and the
      // else block have the same end id for an instruction that is
      // being used in the join block and defined before the if/else.
      if (existingId == endId) return;
      LiveInterval range =
          liveIntervals.putIfAbsent(instruction, () => new LiveInterval());
      range.add(new LiveRange(other.startId, existingId));
      liveInstructions[instruction] = endId;
    });
    other.loopMarkers.forEach((k, v) {
      loopMarkers[k] = v;
    });
  }

  void addLoopMarker(HBasicBlock header, int id) {
    assert(!loopMarkers.containsKey(header));
    loopMarkers[header] = id;
  }

  void removeLoopMarker(HBasicBlock header) {
    assert(loopMarkers.containsKey(header));
    loopMarkers.remove(header);
  }

  bool get isEmpty => liveInstructions.isEmpty && loopMarkers.isEmpty;
  bool contains(HInstruction instruction) =>
      liveInstructions.containsKey(instruction);
  @override
  String toString() => liveInstructions.toString();
}

/// Builds the live intervals of each instruction. The algorithm visits
/// the graph post-dominator tree to find the last uses of an
/// instruction, and computes the liveIns of each basic block.
class SsaLiveIntervalBuilder extends HBaseVisitor with CodegenPhase {
  final Set<HInstruction> generateAtUseSite;
  final Set<HInstruction> controlFlowOperators;

  /// A counter to assign start and end ids to live ranges. The initial
  /// value is not relevant. Note that instructionId goes downward to ease
  /// reasoning about live ranges (the first instruction of a graph has
  /// the lowest id).
  int instructionId = 0;

  /// The liveIns of basic blocks.
  final Map<HBasicBlock, LiveEnvironment> liveInstructions;

  /// The live intervals of instructions.
  final Map<HInstruction, LiveInterval> liveIntervals;

  SsaLiveIntervalBuilder(this.generateAtUseSite, this.controlFlowOperators)
      : liveInstructions = new Map<HBasicBlock, LiveEnvironment>(),
        liveIntervals = new Map<HInstruction, LiveInterval>();

  @override
  void visitGraph(HGraph graph) {
    visitPostDominatorTree(graph);
    if (!liveInstructions[graph.entry].isEmpty) {
      failedAt(CURRENT_ELEMENT_SPANNABLE, 'LiveIntervalBuilder.');
    }
  }

  void markInputsAsLiveInEnvironment(
      HInstruction instruction, LiveEnvironment environment) {
    for (int i = 0, len = instruction.inputs.length; i < len; i++) {
      markAsLiveInEnvironment(instruction.inputs[i], environment);
    }
  }

  // Returns the non-HCheck instruction, or the last [HCheck] in the
  // check chain that is not generate at use site.
  //
  // For example:
  //
  //     t1 = GeneratedAtUseSite instruction
  //     t2 = check(t1)
  //     t3 = check(t2)
  //     t4 = use(t3)
  //     t5 = use(t3)
  //     t6 = use(t2)
  //
  // The t1 is generate-at-use site, and the live-range must thus be on t2 and
  // not on the checked instruction t1.
  // When looking for the checkedInstructionOrNonGenerateAtUseSite of t3 we must
  // return t2.
  HInstruction checkedInstructionOrNonGenerateAtUseSite(HCheck check) {
    dynamic checked = check.checkedInput;
    while (checked is HCheck) {
      HInstruction next = checked.checkedInput;
      if (generateAtUseSite.contains(next)) break;
      checked = next;
    }
    return checked;
  }

  void markAsLiveInEnvironment(
      HInstruction instruction, LiveEnvironment environment) {
    if (generateAtUseSite.contains(instruction)) {
      markInputsAsLiveInEnvironment(instruction, environment);
    } else {
      environment.add(instruction, instructionId);
      // Special case the HCheck instruction to mark the actual
      // checked instruction live. The checked instruction and the
      // [HCheck] will share the same live ranges.
      if (instruction is HCheck) {
        HCheck check = instruction;
        HInstruction checked = checkedInstructionOrNonGenerateAtUseSite(check);
        if (!generateAtUseSite.contains(checked)) {
          environment.add(checked, instructionId);
        }
      }
    }
  }

  void removeFromEnvironment(
      HInstruction instruction, LiveEnvironment environment) {
    environment.remove(instruction, instructionId);
    // Special case the HCheck instruction to have the same live
    // interval as the instruction it is checking.
    if (instruction is HCheck) {
      HCheck check = instruction;
      HInstruction checked = checkedInstructionOrNonGenerateAtUseSite(check);
      if (!generateAtUseSite.contains(checked)) {
        liveIntervals.putIfAbsent(checked, () => new LiveInterval());
        // Unconditionally force the live ranges of the HCheck to
        // be the live ranges of the instruction it is checking.
        liveIntervals[instruction] =
            new LiveInterval.forCheck(instructionId, liveIntervals[checked]);
      }
    }
  }

  @override
  void visitBasicBlock(HBasicBlock block) {
    LiveEnvironment environment =
        new LiveEnvironment(liveIntervals, instructionId);

    // If the control flow instruction in this block will actually be
    // inlined in the codegen in the join block, we need to make
    // whatever is used by that control flow instruction as live in
    // the join block.
    if (controlFlowOperators.contains(block.last)) {
      HIf ifInstruction = block.last;
      HBasicBlock joinBlock = ifInstruction.joinBlock;
      if (generateAtUseSite.contains(joinBlock.phis.first)) {
        markInputsAsLiveInEnvironment(
            ifInstruction, liveInstructions[joinBlock]);
      }
    }

    // Add to the environment the liveIn of its successor, as well as
    // the inputs of the phis of the successor that flow from this block.
    for (int i = 0; i < block.successors.length; i++) {
      HBasicBlock successor = block.successors[i];
      LiveEnvironment successorEnv = liveInstructions[successor];
      if (successorEnv != null) {
        environment.mergeWith(successorEnv);
      } else {
        environment.addLoopMarker(successor, instructionId);
      }

      int index = successor.predecessors.indexOf(block);
      for (HPhi phi = successor.phis.first; phi != null; phi = phi.next) {
        markAsLiveInEnvironment(phi.inputs[index], environment);
      }
    }

    // Iterate over all instructions to remove an instruction from the
    // environment and add its inputs.
    HInstruction instruction = block.last;
    while (instruction != null) {
      if (!generateAtUseSite.contains(instruction)) {
        removeFromEnvironment(instruction, environment);
        markInputsAsLiveInEnvironment(instruction, environment);
      }
      instructionId--;
      instruction = instruction.previous;
    }

    // We just remove the phis from the environment. The inputs of the
    // phis will be put in the environment of the predecessors.
    for (HPhi phi = block.phis.first; phi != null; phi = phi.next) {
      if (!generateAtUseSite.contains(phi)) {
        environment.remove(phi, instructionId);
      }
    }

    // Save the liveInstructions of that block.
    environment.startId = instructionId + 1;
    liveInstructions[block] = environment;

    // If the block is a loop header, we can remove the loop marker,
    // because it will just recompute the loop phis.
    // We also check if this loop header has any back edges. If not,
    // we know there is no loop marker for it.
    if (block.isLoopHeader() && block.predecessors.length > 1) {
      updateLoopMarker(block);
    }
  }

  void updateLoopMarker(HBasicBlock header) {
    LiveEnvironment env = liveInstructions[header];
    int lastId = env.loopMarkers[header];
    // Update all instructions that are liveIns in [header] to have a
    // range that covers the loop.
    env.liveInstructions.forEach((HInstruction instruction, int id) {
      LiveInterval range =
          env.liveIntervals.putIfAbsent(instruction, () => new LiveInterval());
      range.loopUpdate(env.startId, lastId);
      env.liveInstructions[instruction] = lastId;
    });

    env.removeLoopMarker(header);

    // Update all liveIns set to contain the liveIns of [header].
    liveInstructions.forEach((HBasicBlock block, LiveEnvironment other) {
      if (other.loopMarkers.containsKey(header)) {
        env.liveInstructions.forEach((HInstruction instruction, int id) {
          other.liveInstructions[instruction] = id;
        });
        other.removeLoopMarker(header);
        env.loopMarkers.forEach((k, v) {
          other.loopMarkers[k] = v;
        });
      }
    });
  }
}

/// Represents a copy from one instruction to another. The codegen
/// also uses this class to represent a copy from one variable to
/// another.
class Copy<T> {
  final T source;
  final T destination;

  Copy(this.source, this.destination);

  @override
  String toString() => '$destination <- $source';
}

/// A copy handler contains the copies that a basic block needs to do
/// after executing all its instructions.
class CopyHandler {
  /// The copies from an instruction to a phi of the successor.
  final List<Copy<HInstruction>> copies;

  /// Assignments from an instruction that does not need a name (e.g. a
  /// constant) to the phi of a successor.
  final List<Copy<HInstruction>> assignments;

  CopyHandler()
      : copies = <Copy<HInstruction>>[],
        assignments = <Copy<HInstruction>>[];

  void addCopy(HInstruction source, HInstruction destination) {
    copies.add(new Copy<HInstruction>(source, destination));
  }

  void addAssignment(HInstruction source, HInstruction destination) {
    assignments.add(new Copy<HInstruction>(source, destination));
  }

  @override
  String toString() => 'Copies: $copies, assignments: $assignments';

  bool get isEmpty => copies.isEmpty && assignments.isEmpty;
}

/// Contains the mapping between instructions and their names for code
/// generation, as well as the [CopyHandler] for each basic block.
class VariableNames {
  final Map<HInstruction, String> ownName;
  final Map<HBasicBlock, CopyHandler> copyHandlers;

  // Used to control heuristic that determines how local variables are declared.
  final Set<String> allUsedNames;

  /// Name that is used as a temporary to break cycles in
  /// parallel copies. We make sure this name is not being used
  /// anywhere by reserving it when we allocate names for instructions.
  final String swapTemp;

  String getSwapTemp() {
    allUsedNames.add(swapTemp);
    return swapTemp;
  }

  VariableNames()
      : ownName = new Map<HInstruction, String>(),
        copyHandlers = new Map<HBasicBlock, CopyHandler>(),
        allUsedNames = new Set<String>(),
        swapTemp = 't0';

  int get numberOfVariables => allUsedNames.length;

  String getName(HInstruction instruction) {
    return ownName[instruction];
  }

  CopyHandler getCopyHandler(HBasicBlock block) {
    return copyHandlers[block];
  }

  void addNameUsed(String name) {
    allUsedNames.add(name);
  }

  bool hasName(HInstruction instruction) => ownName.containsKey(instruction);

  void addCopy(HBasicBlock block, HInstruction source, HPhi destination) {
    CopyHandler handler =
        copyHandlers.putIfAbsent(block, () => new CopyHandler());
    handler.addCopy(source, destination);
  }

  void addAssignment(HBasicBlock block, HInstruction source, HPhi destination) {
    CopyHandler handler =
        copyHandlers.putIfAbsent(block, () => new CopyHandler());
    handler.addAssignment(source, destination);
  }
}

/// Allocates variable names for instructions, making sure they don't collide.
class VariableNamer {
  final VariableNames names;
  final ModularNamer _namer;
  final Set<String> usedNames;
  final List<String> freeTemporaryNames;
  int temporaryIndex = 0;
  static final RegExp regexp = new RegExp('t[0-9]+');

  VariableNamer(LiveEnvironment environment, this.names, this._namer)
      : usedNames = new Set<String>(),
        freeTemporaryNames = <String>[] {
    // [VariableNames.swapTemp] is used when there is a cycle in a copy handler.
    // Therefore we make sure no one uses it.
    usedNames.add(names.swapTemp);

    // All liveIns instructions must have a name at this point, so we
    // add them to the list of used names.
    environment.liveInstructions.forEach((HInstruction instruction, int index) {
      String name = names.getName(instruction);
      if (name != null) {
        usedNames.add(name);
        names.addNameUsed(name);
      }
    });
  }

  String allocateWithHint(String originalName) {
    int i = 0;
    String name = _namer.safeVariableName(originalName);
    while (usedNames.contains(name)) {
      name = _namer.safeVariableName('$originalName${i++}');
    }
    return name;
  }

  String allocateTemporary() {
    while (!freeTemporaryNames.isEmpty) {
      String name = freeTemporaryNames.removeLast();
      if (!usedNames.contains(name)) return name;
    }
    String name = 't${temporaryIndex++}';
    while (usedNames.contains(name)) name = 't${temporaryIndex++}';
    return name;
  }

  HPhi firstPhiUserWithElement(HInstruction instruction) {
    for (HInstruction user in instruction.usedBy) {
      if (user is HPhi && user.sourceElement != null) {
        return user;
      }
    }
    return null;
  }

  String allocateName(HInstruction instruction) {
    String name;
    if (instruction is HCheck) {
      // Special case this instruction to use the name of its
      // input if it has one.
      HInstruction temp = instruction;
      do {
        temp = (temp as HCheck).checkedInput;
        name = names.ownName[temp];
      } while (name == null && temp is HCheck);
      if (name != null) return addAllocatedName(instruction, name);
    }

    if (instruction.sourceElement != null) {
      if (instruction.sourceElement.name != null) {
        name = allocateWithHint(instruction.sourceElement.name);
      } else {
        // Source element is synthesized and has no name.
        name = allocateTemporary();
      }
    } else {
      // We could not find an element for the instruction. If the
      // instruction is used by a phi, try to use the name of the phi.
      // Otherwise, just allocate a temporary name.
      HPhi phi = firstPhiUserWithElement(instruction);
      if (phi != null && phi.sourceElement.name != null) {
        name = allocateWithHint(phi.sourceElement.name);
      } else {
        name = allocateTemporary();
      }
    }
    return addAllocatedName(instruction, name);
  }

  String addAllocatedName(HInstruction instruction, String name) {
    usedNames.add(name);
    names.addNameUsed(name);
    names.ownName[instruction] = name;
    return name;
  }

  /// Frees [instruction]'s name so it can be used for other instructions.
  void freeName(HInstruction instruction) {
    String ownName = names.ownName[instruction];
    if (ownName != null) {
      // We check if we have already looked for temporary names
      // because if we haven't, chances are the temporary we allocate
      // in this block can match a phi with the same name in the
      // successor block.
      if (temporaryIndex != 0 && regexp.hasMatch(ownName)) {
        freeTemporaryNames.add(ownName);
      }
      usedNames.remove(ownName);
    }
  }
}

/// Visits all blocks in the graph, sets names to instructions, and
/// creates the [CopyHandler] for each block. This class needs to have
/// the liveIns set as well as all the live intervals of instructions.
/// It visits the graph in dominator order, so that at each entry of a
/// block, the instructions in its liveIns set have names.
///
/// When visiting a block, it goes through all instructions. For each
/// instruction, it frees the names of the inputs that die at that
/// instruction, and allocates a name to the instruction. For each phi,
/// it adds a copy to the CopyHandler of the corresponding predecessor.
class SsaVariableAllocator extends HBaseVisitor with CodegenPhase {
  final ModularNamer _namer;
  final Map<HBasicBlock, LiveEnvironment> liveInstructions;
  final Map<HInstruction, LiveInterval> liveIntervals;
  final Set<HInstruction> generateAtUseSite;

  final VariableNames names;

  SsaVariableAllocator(this._namer, this.liveInstructions, this.liveIntervals,
      this.generateAtUseSite)
      : this.names = new VariableNames();

  @override
  void visitGraph(HGraph graph) {
    visitDominatorTree(graph);
  }

  @override
  void visitBasicBlock(HBasicBlock block) {
    VariableNamer variableNamer =
        new VariableNamer(liveInstructions[block], names, _namer);

    block.forEachPhi((HPhi phi) {
      handlePhi(phi, variableNamer);
    });

    block.forEachInstruction((HInstruction instruction) {
      handleInstruction(instruction, variableNamer);
    });
  }

  /// Returns whether [instruction] needs a name. Instructions that
  /// have no users or that are generated at use site do not need a name.
  bool needsName(instruction) {
    if (instruction is HThis) return false;
    if (instruction is HParameterValue) return true;
    if (instruction.usedBy.isEmpty) return false;
    if (generateAtUseSite.contains(instruction)) return false;
    return !instruction.nonCheck().isCodeMotionInvariant();
  }

  /// Returns whether [instruction] dies at the instruction [at].
  bool diesAt(HInstruction instruction, HInstruction at) {
    LiveInterval atInterval = liveIntervals[at];
    LiveInterval instructionInterval = liveIntervals[instruction];
    int start = atInterval.start;
    return instructionInterval.diesAt(start);
  }

  void freeUsedNamesAt(
      HInstruction instruction, HInstruction at, VariableNamer namer) {
    if (needsName(instruction)) {
      if (diesAt(instruction, at)) {
        namer.freeName(instruction);
      }
    } else if (generateAtUseSite.contains(instruction)) {
      // If the instruction is generated at use site, then all its
      // inputs may also die at [at].
      for (int i = 0, len = instruction.inputs.length; i < len; i++) {
        HInstruction input = instruction.inputs[i];
        freeUsedNamesAt(input, at, namer);
      }
    }
  }

  void handleInstruction(HInstruction instruction, VariableNamer namer) {
    if (generateAtUseSite.contains(instruction)) {
      assert(!liveIntervals.containsKey(instruction));
      return;
    }

    for (int i = 0, len = instruction.inputs.length; i < len; i++) {
      HInstruction input = instruction.inputs[i];
      freeUsedNamesAt(input, instruction, namer);
    }

    if (needsName(instruction)) {
      namer.allocateName(instruction);
    }
  }

  void handlePhi(HPhi phi, VariableNamer namer) {
    if (!needsName(phi)) return;

    for (int i = 0; i < phi.inputs.length; i++) {
      HInstruction input = phi.inputs[i];
      HBasicBlock predecessor = phi.block.predecessors[i];
      // A [HTypeKnown] instruction never has a name, but its checked
      // input might, therefore we need to do a copy instead of an
      // assignment.
      while (input is HTypeKnown) input = input.inputs[0];
      if (!needsName(input)) {
        names.addAssignment(predecessor, input, phi);
      } else {
        names.addCopy(predecessor, input, phi);
      }
    }

    namer.allocateName(phi);
  }
}
