//===--- GlobalLoopARCSequenceDataflow.h ------------------------*- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

#ifndef SWIFT_SILOPTIMIZER_PASSMANAGER_ARC_GLOBALLOOPARCSEQUENCEDATAFLOW_H
#define SWIFT_SILOPTIMIZER_PASSMANAGER_ARC_GLOBALLOOPARCSEQUENCEDATAFLOW_H

#include "RefCountState.h"
#include "swift/SILOptimizer/Analysis/LoopRegionAnalysis.h"
#include "swift/SILOptimizer/Analysis/ProgramTerminationAnalysis.h"
#include "swift/Basic/BlotMapVector.h"
#include "swift/Basic/NullablePtr.h"
#include "swift/Basic/ImmutablePointerSet.h"
#include "llvm/ADT/MapVector.h"
#include "llvm/ADT/Optional.h"

namespace swift {

class SILFunction;
class AliasAnalysis;

} // end swift namespace

namespace swift {

// Forward declaration of private classes that are opaque in this header.
class ARCRegionState;

/// A class that implements the ARC sequence data flow.
class LoopARCSequenceDataflowEvaluator {
  /// The bump ptr allocator that is used to allocate memory in the allocator.
  llvm::BumpPtrAllocator Allocator;

  /// The factory that we use to generate immutable pointer sets.
  ImmutablePointerSetFactory<SILInstruction> SetFactory;

  /// The SILFunction that we are applying the dataflow to.
  SILFunction &F;

  /// The alias analysis that we are using for alias queries.
  AliasAnalysis *AA;

  /// Loop region information that we use to perform dataflow up and down the
  /// loop nest.
  LoopRegionFunctionInfo *LRFI;

  /// The loop info we use for convenience to seed our traversals.
  SILLoopInfo *SLI;

  /// An analysis which computes the identity root of a SILValue(), i.e. the
  /// dominating origin SILValue of the reference count that by retaining or
  /// releasing this value one is affecting.
  RCIdentityFunctionInfo *RCFI;

  /// An analysis to get the epilogue ARC instructions. 
  EpilogueARCFunctionInfo *EAFI;

  /// The map from dataflow terminating decrements -> increment dataflow state.
  BlotMapVector<SILInstruction *, TopDownRefCountState> &DecToIncStateMap;

  /// The map from dataflow terminating increment -> decrement dataflow state.
  BlotMapVector<SILInstruction *, BottomUpRefCountState> &IncToDecStateMap;

  /// Stashed information for each region.
  llvm::DenseMap<const LoopRegion *, ARCRegionState *> RegionStateInfo;

public:
  LoopARCSequenceDataflowEvaluator(
      SILFunction &F, AliasAnalysis *AA, LoopRegionFunctionInfo *LRFI,
      SILLoopInfo *SLI, RCIdentityFunctionInfo *RCIA,
      EpilogueARCFunctionInfo *EAFI,
      ProgramTerminationFunctionInfo *PTFI,
      BlotMapVector<SILInstruction *, TopDownRefCountState> &DecToIncStateMap,
      BlotMapVector<SILInstruction *, BottomUpRefCountState> &IncToDecStateMap);
  ~LoopARCSequenceDataflowEvaluator();

  SILFunction *getFunction() const { return &F; }

  /// Clear all of the state associated with the given loop.
  void clearLoopState(const LoopRegion *R);

  /// Perform the sequence dataflow, bottom up and top down on the loop region
  /// \p R.
  bool runOnLoop(const LoopRegion *R, bool FreezeOwnedArgEpilogueReleases,
                 bool RecomputePostDomReleases);

  /// Summarize the subregions of \p R that are blocks.
  ///
  /// We assume that all subregions that are loops have already been summarized
  /// since we are processing bottom up through the loop nest hierarchy.
  void summarizeSubregionBlocks(const LoopRegion *R);

  /// Summarize the contents of the loop so that loops further up the loop tree
  /// can reason about the loop.
  void summarizeLoop(const LoopRegion *R);

  /// Add \p I to the interesting instruction list of its parent block.
  void addInterestingInst(SILInstruction *I);

  /// Remove \p I from the interesting instruction list of its parent block.
  void removeInterestingInst(SILInstruction *I);

  /// Clear the folding node set of the set factory we have stored internally.
  void clearSetFactory() {
    SetFactory.clear();
  }

private:
  /// Merge in the BottomUp state of any successors of DataHandle.getBB() into
  /// DataHandle.getState().
  void mergeSuccessors(const LoopRegion *R, ARCRegionState &State);

  /// Merge in the TopDown state of any predecessors of DataHandle.getBB() into
  /// DataHandle.getState().
  void mergePredecessors(const LoopRegion *R, ARCRegionState &State);

  void computePostDominatingConsumedArgMap();

  ARCRegionState &getARCState(const LoopRegion *L) {
    auto Iter = RegionStateInfo.find(L);
    assert(Iter != RegionStateInfo.end() && "Should have created state for "
                                            "each region");
    return *Iter->second;
  }

  bool processLoopTopDown(const LoopRegion *R);
  bool processLoopBottomUp(const LoopRegion *R,
                           bool FreezeOwnedArgEpilogueReleases);
};

} // end swift namespace

#endif
