text: /*
     +----------------------------------------------------------------------+
     | HipHop for PHP                                                       |
     +----------------------------------------------------------------------+
     | Copyright (c) 2010-present Facebook, Inc. (http://www.facebook.com)  |
     +----------------------------------------------------------------------+
     | This source file is subject to version 3.01 of the PHP license,      |
     | that is bundled with this package in the file LICENSE, and is        |
     | available through the world-wide-web at the following url:           |
     | http://www.php.net/license/3_01.txt                                  |
     | If you did not receive a copy of the PHP license and are unable to   |
     | obtain it through the world-wide-web, please send a note to          |
     | license@php.net so we can mail you a copy immediately.               |
     +----------------------------------------------------------------------+
  */
  
  #ifndef incl_HPHP_IR_UNIT_H_
  #define incl_HPHP_IR_UNIT_H_
  
  #include "hphp/runtime/vm/jit/annotation-data.h"
  #include "hphp/runtime/vm/jit/block.h"
  #include "hphp/runtime/vm/jit/check.h"
  #include "hphp/runtime/vm/jit/containers.h"
  #include "hphp/runtime/vm/jit/ir-instr-table.h"
  #include "hphp/runtime/vm/jit/ir-opcode.h"
  #include "hphp/runtime/vm/jit/region-selection.h"
  #include "hphp/runtime/vm/jit/translator.h"
  
  #include "hphp/util/arena.h"
  #include "hphp/util/struct-log.h"
  
  #include <string>
  #include <type_traits>
  #include <folly/Optional.h>
  
  namespace HPHP {
  //////////////////////////////////////////////////////////////////////
  
  struct SrcKey;
  
  namespace jit {
  
  //////////////////////////////////////////////////////////////////////
  
  struct Block;
  struct IRInstruction;
  struct SSATmp;
  
  //////////////////////////////////////////////////////////////////////
  
  /*
   * Create an IRInstruction on the stack using `args', and call `func' with a
   * pointer to it, returning the result.
   *
   * Normally IRInstruction creation should go through either IRUnit::gen or
   * IRBuilder::gen.  This utility is used to implement those.
   *
   * The IRInstruction* must not escape `func'---the aforementioned gen() methods
   * use IRUnit::clone() to duplicate the instruction in arena memory.
   */
  template<class Func, class... Args>
  typename std::result_of<Func(IRInstruction*)>::type
  makeInstruction(Func func, Args&&... args);
  
  //////////////////////////////////////////////////////////////////////
  
  /*
   * Map from DefLabel instructions to produced references.
   *
   * See comment in IRBuilder::cond for more details.
   */
  using LabelRefs = jit::hash_map<const IRInstruction*, jit::vector<uint32_t>>;
  
  //////////////////////////////////////////////////////////////////////
  
  /*
   * IRUnit is the compilation unit for the JIT.  It owns an Arena used for
   * allocating and controlling the lifetime of Block, IRInstruction, ExtraData,
   * and SSATmp objects, as well as a constant table containing all DefConst
   * instructions, which don't live in Blocks.
   *
   * IRUnit also assigns unique ids to each block, instruction, and tmp, which
   * are useful for StateVector or sparse maps of pass-specific information.
   */
  struct IRUnit {
    /*
     * Construct an IRUnit with a single, empty entry Block.
     */
    explicit IRUnit(TransContext context,
                    std::unique_ptr<AnnotationData> = nullptr);
  
  
    /////////////////////////////////////////////////////////////////////////////
    // Instruction creation.
  
    /*
     * Create an IRInstruction with lifetime equivalent to this IRUnit.
     *
     * Arguments are passed in the following format:
     *
     *   gen(Opcode op,
     *       BCMarker marker,
     *       const IRExtraData&   // optional
     *       Type typeParam,      // optional
     *       Block* target,       // optional
     *       SSATmp* srcs...
     *   );
     *
     * Optional arguments can be ordered arbitrarily.  The `srcs' must come last,
     * and can be specified either as a varargs list of SSATmp*'s, or as a pair
     * of (number of tmps, SSATmp**).  Zero `srcs' is allowed.
     */
    template<class... Args>
    IRInstruction* gen(Args&&... args);
  
    /*
     * Create an IRInstruction with a pre-allocated destination operand.
     *
     * The `dst' argument will be retyped to match the newly generated
     * instruction.
     *
     * This function takes arguments in the same format as gen().
     */
    template<class... Args>
    IRInstruction* gen(SSATmp* dst, Args&&... args);
  
    /*
     * Replace an existing IRInstruction with a new one.
     *
     * This may involve making more allocations in the arena, but the actual
     * IRInstruction itself (i.e., its address, its ID, its BCMarker, etc.) will
     * stay unchanged.
     *
     * This function takes arguments in the same format as gen(), except that the
     * BCMarker is omitted.
     */
    template<class... Args>
    void replace(IRInstruction* old, Opcode op, Args... args);
  
    /*
     * Deep-copy an IRInstruction and its srcs/dsts into arena-allocated memory.
     *
     * If provided, `dst' will be used as the clone's `dst' instead of a newly-
     * allocated SSATmp.
     */
    IRInstruction* clone(const IRInstruction* inst, SSATmp* dst = nullptr);
  
  
    /////////////////////////////////////////////////////////////////////////////
    // Accessors.
  
    /*
     * Basic getters.
     */
    Arena&              arena();
    const TransContext& context() const;
    Block*              entry() const;
    // TODO(#3538578): The above should return `const Block*'.
  
    /*
     * Starting position, from the TransContext.
     */
    SrcKey initSrcKey() const;
  
    /*
     * Counts of the number of SSATmps, Blocks, and IRInstructions allocated in
     * this IRUnit's arena.
     *
     * Note that these are /not/ the counts of these objects in the Unit's CFG;
     * they merely track the number of objects we have assigned IDs to.
     */
    uint32_t numTmps() const;
    uint32_t numBlocks() const;
    uint32_t numInsts() const;
  
    /*
     * Overloads useful for StateVector and IdSet.
     */
    uint32_t numIds(const SSATmp*) const;
    uint32_t numIds(const Block*) const;
    uint32_t numIds(const IRInstruction*) const;
  
    /*
     * Find an SSATmp* from an id.
     */
    SSATmp* findSSATmp(uint32_t id) const;
  
    /*
     * Return the main FramePtr for the unit.  This is the result of the DefFP
     * instruction on the entry block.
     */
    SSATmp* mainFP() const;
  
    /*
     * Return the main StkPtr for the unit.  This is the result of the DefSP
     * instruction on the entry block. (note that tere should be no other stack
     * pointers in the unit).
     */
    SSATmp* mainSP() const;
  
    /*
     * Return the "start" timestamp when this IRUnit was constructed.
     */
    int64_t startNanos() const;
    folly::Optional<StructuredLogEntry>& logEntry() const;
    void initLogEntry(const Func*);
  
    /////////////////////////////////////////////////////////////////////////////
  
    struct Hinter {
      Hinter(IRUnit& unit, Block::Hint defHint) :
          m_unit(unit), m_saved(unit.m_defHint) {
        m_unit.m_defHint = defHint;
      }
      ~Hinter() {
        m_unit.m_defHint = m_saved;
      }
     private:
      IRUnit& m_unit;
      Block::Hint m_saved;
    };
  
    /*
     * Add a block to the IRUnit's arena.
     */
    Block* defBlock(uint64_t profCount = 1,
                    Block::Hint hint = Block::Hint::Neither);
  
    /*
     * Add a DefConst instruction to the const table.
     */
    template<typename T>
    SSATmp* cns(T val);
    SSATmp* cns(Type type);
  
    /*
     * Create a DefLabel instruction.
     */
    IRInstruction* defLabel(unsigned numDst, BCContext bcctx);
  
    /*
     * Add some extra destinations to a defLabel.
     */
    void expandLabel(IRInstruction* label, unsigned extraDst);
  
    /*
     * Add an extra SSATmp to jmp.
     */
    void expandJmp(IRInstruction* jmp, SSATmp* value);
  
    /////////////////////////////////////////////////////////////////////////////
    // Annotation data
    std::unique_ptr<AnnotationData> annotationData;
  
  private:
    template<class... Args> SSATmp* newSSATmp(Args&&...);
  
  private:
    // Contains Block, IRInstruction, and SSATmp objects.
    Arena m_arena;
  
    // DefConsts for each unique constant in this IR.
    IRInstrTable m_constTable;
  
    // Translation context for which this IRUnit was created.
    TransContext const m_context;
  
    // Counters for m_arena allocations.
    uint32_t m_nextBlockId{0};
    uint32_t m_nextInstId{0};
  
    // Entry point.
    Block* m_entry;
  
    // Map from SSATmp ids to SSATmp*.
    jit::vector<SSATmp*> m_ssaTmps;
  
    // Default hint value for new blocks in this unit.
    Block::Hint m_defHint{Block::Hint::Neither};
  
    int64_t m_startNanos; // Timestamp at construction time.
    mutable folly::Optional<StructuredLogEntry> m_logEntry;
  };
  
  //////////////////////////////////////////////////////////////////////
  
  /*
   * Create a debug string for an IRUnit.
   */
  std::string show(const IRUnit&);
  
  //////////////////////////////////////////////////////////////////////
  
  /*
   * Find and return a unique block that ends the unit at lastSk.
   *
   * If one cannot be found, abort, unless the unit has 0 main exits and 1 or
   * more blocks that end with Unreachable, in which case return nullptr. This
   * indicates regions that ended early due to type contradictions.
   */
  Block* findMainExitBlock(const IRUnit& unit, SrcKey lastSk);
  
  //////////////////////////////////////////////////////////////////////
  
  }}
  
  #include "hphp/runtime/vm/jit/ir-unit-inl.h"
  
  #endif
  