//===-- llvm/CodeGen/RenderMachineFunction.h - MF->HTML -*- C++ -*---------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_CODEGEN_RENDERMACHINEFUNCTION_H
#define LLVM_CODEGEN_RENDERMACHINEFUNCTION_H

#include "llvm/CodeGen/LiveInterval.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/SlotIndexes.h"
#include "llvm/Target/TargetRegisterInfo.h"

#include <algorithm>
#include <map>
#include <set>
#include <string>

namespace llvm {

  class LiveInterval;
  class LiveIntervals;
  class MachineInstr;
  class MachineRegisterInfo;
  class RenderMachineFunction;
  class TargetRegisterClass;
  class TargetRegisterInfo;
  class VirtRegMap;
  class raw_ostream;

  /// \brief Helper class to process rendering options. Tries to be as lazy as
  ///        possible.
  class MFRenderingOptions {
  public:

    struct RegClassComp {
      bool operator()(const TargetRegisterClass *trc1,
                      const TargetRegisterClass *trc2) const {
        std::string trc1Name(trc1->getName()), trc2Name(trc2->getName());
        return std::lexicographical_compare(trc1Name.begin(), trc1Name.end(),
                                            trc2Name.begin(), trc2Name.end());
      }
    };

    typedef std::set<const TargetRegisterClass*, RegClassComp> RegClassSet;

    struct IntervalComp {
      bool operator()(const LiveInterval *li1, const LiveInterval *li2) const {
        return li1->reg < li2->reg;
      }
    };

    typedef std::set<const LiveInterval*, IntervalComp> IntervalSet;

    /// Initialise the rendering options.
    void setup(MachineFunction *mf, const TargetRegisterInfo *tri,
               LiveIntervals *lis, const RenderMachineFunction *rmf);

    /// Clear translations of options to the current function.
    void clear();

    /// Reset any options computed for this specific rendering.
    void resetRenderSpecificOptions();

    /// Should we render the current function.
    bool shouldRenderCurrentMachineFunction() const;

    /// Return the set of register classes to render pressure for.
    const RegClassSet& regClasses() const;

    /// Return the set of live intervals to render liveness for.
    const IntervalSet& intervals() const;

    /// Render indexes which are not associated with instructions / MBB starts.
    bool renderEmptyIndexes() const;

    /// Return whether or not to render using SVG for fancy vertical text.
    bool fancyVerticals() const;

  private:

    static bool renderingOptionsProcessed;
    static std::set<std::string> mfNamesToRender;
    static bool renderAllMFs;

    static std::set<std::string> classNamesToRender;
    static bool renderAllClasses;


    static std::set<std::pair<unsigned, unsigned> > intervalNumsToRender;
    typedef enum { ExplicitOnly     = 0,
                   AllPhys          = 1,
                   VirtNoSpills     = 2,
                   VirtSpills       = 4,
                   AllVirt          = 6,
                   All              = 7 }
      IntervalTypesToRender;
    static unsigned intervalTypesToRender;

    template <typename OutputItr>
    static void splitComaSeperatedList(const std::string &s, OutputItr outItr);

    static void processOptions();

    static void processFuncNames();
    static void processRegClassNames();
    static void processIntervalNumbers();

    static void processIntervalRange(const std::string &intervalRangeStr);

    MachineFunction *mf;
    const TargetRegisterInfo *tri;
    LiveIntervals *lis;
    const RenderMachineFunction *rmf;

    mutable bool regClassesTranslatedToCurrentFunction;
    mutable RegClassSet regClassSet;

    mutable bool intervalsTranslatedToCurrentFunction;
    mutable IntervalSet intervalSet;

    void translateRegClassNamesToCurrentFunction() const;

    void translateIntervalNumbersToCurrentFunction() const;
  };

  /// \brief Provide extra information about the physical and virtual registers
  ///        in the function being compiled.
  class TargetRegisterExtraInfo {
  public:
    TargetRegisterExtraInfo();

    /// \brief Set up TargetRegisterExtraInfo with pointers to necessary
    ///        sources of information.
    void setup(MachineFunction *mf, MachineRegisterInfo *mri,
               const TargetRegisterInfo *tri, LiveIntervals *lis);

    /// \brief Recompute tables for changed function.
    void reset(); 

    /// \brief Free all tables in TargetRegisterExtraInfo.
    void clear();

    /// \brief Maximum number of registers from trc which alias reg.
    unsigned getWorst(unsigned reg, const TargetRegisterClass *trc) const;

    /// \brief Returns the number of allocable registers in trc.
    unsigned getCapacity(const TargetRegisterClass *trc) const;

    /// \brief Return the number of registers of class trc that may be
    ///        needed at slot i.
    unsigned getPressureAtSlot(const TargetRegisterClass *trc,
                               SlotIndex i) const;

    /// \brief Return true if the number of registers of type trc that may be
    ///        needed at slot i is greater than the capacity of trc.
    bool classOverCapacityAtSlot(const TargetRegisterClass *trc,
                                 SlotIndex i) const;

  private:

    MachineFunction *mf;
    MachineRegisterInfo *mri;
    const TargetRegisterInfo *tri;
    LiveIntervals *lis;

    typedef std::map<const TargetRegisterClass*, unsigned> WorstMapLine;
    typedef std::map<const TargetRegisterClass*, WorstMapLine> VRWorstMap;
    VRWorstMap vrWorst;

    typedef std::map<unsigned, WorstMapLine> PRWorstMap;
    PRWorstMap prWorst;

    typedef std::map<const TargetRegisterClass*, unsigned> CapacityMap;
    CapacityMap capacityMap;

    typedef std::map<const TargetRegisterClass*, unsigned> PressureMapLine;
    typedef std::map<SlotIndex, PressureMapLine> PressureMap;
    PressureMap pressureMap;

    bool mapsPopulated;

    /// \brief Initialise the 'worst' table.
    void initWorst();
 
    /// \brief Initialise the 'capacity' table.
    void initCapacity();

    /// \brief Initialise/Reset the 'pressure' and live states tables.
    void resetPressureAndLiveStates();
  };

  /// \brief Render MachineFunction objects and related information to a HTML
  ///        page.
  class RenderMachineFunction : public MachineFunctionPass {
  public:
    static char ID;

    RenderMachineFunction() : MachineFunctionPass(ID) {}

    virtual void getAnalysisUsage(AnalysisUsage &au) const;

    virtual bool runOnMachineFunction(MachineFunction &fn);

    virtual void releaseMemory();

    void rememberUseDefs(const LiveInterval *li);

    void rememberSpills(const LiveInterval *li,
                        const std::vector<LiveInterval*> &spills);

    bool isSpill(const LiveInterval *li) const;

    /// \brief Render this machine function to HTML.
    /// 
    /// @param renderContextStr This parameter will be included in the top of
    ///                         the html file to explain where (in the
    ///                         codegen pipeline) this function was rendered
    ///                         from. Set it to something like
    ///                         "Pre-register-allocation".
    /// @param vrm              If non-null the VRM will be queried to determine
    ///                         whether a virtual register was allocated to a
    ///                         physical register or spilled.
    /// @param renderFilePrefix This string will be appended to the function
    ///                         name (before the output file suffix) to enable
    ///                         multiple renderings from the same function.
    void renderMachineFunction(const char *renderContextStr,
                               const VirtRegMap *vrm = 0,
                               const char *renderSuffix = 0);

  private:
    class Spacer;
    friend raw_ostream& operator<<(raw_ostream &os, const Spacer &s);

    std::string fqn;

    MachineFunction *mf;
    MachineRegisterInfo *mri;
    const TargetRegisterInfo *tri;
    LiveIntervals *lis;
    SlotIndexes *sis;
    const VirtRegMap *vrm;

    TargetRegisterExtraInfo trei;
    MFRenderingOptions ro;

    

    // Utilities.
    typedef enum { Dead, Defined, Used, AliveReg, AliveStack } LiveState;
    LiveState getLiveStateAt(const LiveInterval *li, SlotIndex i) const;

    typedef enum { Zero, Low, High } PressureState;
    PressureState getPressureStateAt(const TargetRegisterClass *trc,
                                     SlotIndex i) const;

    typedef std::map<const LiveInterval*, std::set<const LiveInterval*> >
      SpillIntervals;
    SpillIntervals spillIntervals;

    typedef std::map<const LiveInterval*, const LiveInterval*> SpillForMap;
    SpillForMap spillFor;

    typedef std::set<SlotIndex> SlotSet;
    typedef std::map<const LiveInterval*, SlotSet> UseDefs;
    UseDefs useDefs;

    // ---------- Rendering methods ----------

    /// For inserting spaces when pretty printing.
    class Spacer {
    public:
      explicit Spacer(unsigned numSpaces) : ns(numSpaces) {}
      Spacer operator+(const Spacer &o) const { return Spacer(ns + o.ns); }
      void print(raw_ostream &os) const;
    private:
      unsigned ns;
    };

    Spacer s(unsigned ns) const;

    template <typename Iterator>
    std::string escapeChars(Iterator sBegin, Iterator sEnd) const;

    /// \brief Render a machine instruction.
    void renderMachineInstr(raw_ostream &os,
                            const MachineInstr *mi) const;

    /// \brief Render vertical text.
    template <typename T>
    void renderVertical(const Spacer &indent,
                        raw_ostream &os,
                        const T &t) const;

    /// \brief Insert CSS layout info.
    void insertCSS(const Spacer &indent,
                   raw_ostream &os) const;

    /// \brief Render a brief summary of the function (including rendering
    ///        context).
    void renderFunctionSummary(const Spacer &indent,
                               raw_ostream &os,
                               const char * const renderContextStr) const;

    /// \brief Render a legend for the pressure table.
    void renderPressureTableLegend(const Spacer &indent,
                                   raw_ostream &os) const;

    /// \brief Render a consecutive set of HTML cells of the same class using
    /// the colspan attribute for run-length encoding.
    template <typename CellType>
    void renderCellsWithRLE(
                     const Spacer &indent, raw_ostream &os,
                     const std::pair<CellType, unsigned> &rleAccumulator,
                     const std::map<CellType, std::string> &cellTypeStrs) const;

    /// \brief Render code listing, potentially with register pressure
    ///        and live intervals shown alongside.
    void renderCodeTablePlusPI(const Spacer &indent,
                               raw_ostream &os) const;

    /// \brief Render the HTML page representing the MachineFunction.
    void renderFunctionPage(raw_ostream &os,
                            const char * const renderContextStr) const;

    std::string escapeChars(const std::string &s) const;
  };
}

#endif /* LLVM_CODEGEN_RENDERMACHINEFUNCTION_H */
