/*===================== begin_copyright_notice ==================================

Copyright (c) 2017 Intel Corporation

Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:

The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.


======================= end_copyright_notice ==================================*/
//
/// GenXNumbering
/// -------------
///
/// GenXNumbering is an analysis that provides a numbering of the instructions
/// for use by live ranges.
///
/// The numbering is done such that slots are reserved for where GenXCoalescing
/// might need to insert copies.
///
/// Generally, an instruction gets a slot in the numbering for itself, and
/// another slot just before, in case it is a two address instruction where
/// GenXCoalescing might want to insert a copy.
///
/// Every instruction gets a number, even if it is baled in. However, for the
/// purposes of live range segments, every instruction in a bale is assumed
/// to have the same number as the head instruction of the bale.
///
/// A non-intrinsic call has N slots reserved
/// before it for pre-copies, where N is the number of SimpleValues in the
/// (possibly struct) args, allowing for extra args that might be added later by
/// GenXArgIndirection.
/// 
/// Similarly, a non-intrinsic call has N slots reserved after it for
/// post-copies, where N is the number of SimpleValues in the (possibly struct)
/// return value. The definition of each SimpleValue in the result of the call
/// is considered to be in its slot, and the corresponding SimpleValue in the
/// unified return value has an extra segment of live range from the call up to
/// that slot.
/// 
/// A return instruction in a subroutine has N slots reserved before it for
/// pre-copies, where N is the number of SimpleValues in the (possibly struct)
/// return value. The use of each SimpleValue in the return is considered to be
/// in its slot, and the corresponding SimpleValue in the unified return value
/// has an extra segment of live range from the slot up to the return.
///
/// A kernel has a slot for each kernel arg copy. A copy is inserted into such a slot in
/// GenXCoalescing if the kernel arg offset is not aligned enough for the uses
/// of the value.
///
/// **IR restriction**: After this pass, it is very difficult to modify code
/// other than by inserting copies in the reserved slots above, as it would
/// disturb the numbering.
///
//===----------------------------------------------------------------------===//
#ifndef GENXNUMBERING_H
#define GENXNUMBERING_H

#include "FunctionGroup.h"
#include "IgnoreRAUWValueMap.h"
#include "llvm/IR/Value.h"

namespace llvm {

class CallInst;
class GenXBaling;
class PHINode;
class ReturnInst;

FunctionGroupPass *createGenXGroupPrinterPass(raw_ostream &O, const std::string &Banner);

class GenXNumbering : public FunctionGroupPass {
  FunctionGroup *FG;
  GenXBaling *Baling;
  struct BBNumber {
    unsigned Index; // 0-based index in list of basic blocks
    unsigned PhiNumber; // instruction number of first phi node in successor
    unsigned EndNumber; // instruction number of end of block
  };
  // BBNumbers : The 0-based number (index) of each basic block.
  ValueMap<const BasicBlock *, BBNumber,
          IgnoreRAUWValueMapConfig<const BasicBlock *>> BBNumbers;
  // Numbers : The map of instruction numbers.
  ValueMap<const Value *, unsigned,
          IgnoreRAUWValueMapConfig<const Value *>> Numbers;
  // StartNumbers : for a CallInst, the start number of where arg pre-copies
  // are considered to be. This is stored, instead of being calculated from
  // the CallInst's number, so that a CallInst can change number of args, as
  // happens in GenXArgIndirection.
  ValueMap<const Value *, unsigned,
          IgnoreRAUWValueMapConfig<const Value *>> StartNumbers;
  // NumberToPhiIncomingMap : map from instruction number to the phi incoming (phi
  //  node plus incoming index) it represents. We assume that a phi node is
  //  never deleted after GenXNumbering.
  std::map<unsigned, std::pair<PHINode *, unsigned>> NumberToPhiIncomingMap;

  // The number for the entire fucntion group. All live ranges are included in
  // live-range [0, LastNum].
  unsigned LastNum = 0;

public:
  static char ID;
  explicit GenXNumbering() : FunctionGroupPass(ID), Baling(0) { }
  ~GenXNumbering() { clear(); }
  virtual StringRef getPassName() const { return "GenX numbering"; }
  void getAnalysisUsage(AnalysisUsage &AU) const;
  bool runOnFunctionGroup(FunctionGroup &FG);
  // get BBNumber struct for a basic block
  const BBNumber *getBBNumber(BasicBlock *BB) { return &BBNumbers[BB]; }
  // get and set instruction number
  unsigned getBaleNumber(Instruction *Inst);
  unsigned getNumber(Value *V);
  unsigned getLastNumber() const { return LastNum; }
  void setNumber(Value *V, unsigned Number);
  // get and set "start instruction number" for a CallInst
  unsigned getStartNumber(Value *V) { return StartNumbers[V]; }
  void setStartNumber(Value *V, unsigned Number) { StartNumbers[V] = Number; }
  // get number for kernel arg copy, arg pre-copy, ret pre-copy and ret post-copy sites
  unsigned getArgIndirectionNumber(CallInst *CI, unsigned OperandNum, unsigned Index);
  unsigned getKernelArgCopyNumber(Argument *Arg);
  unsigned getArgPreCopyNumber(CallInst *CI, unsigned OperandNum, unsigned Index);
  unsigned getRetPreCopyNumber(ReturnInst *RI, unsigned Index);
  unsigned getRetPostCopyNumber(CallInst *CI, unsigned Index);
  // get the number of a phi incoming, where its copy will be inserted
  // if necessary
  unsigned getPhiNumber(PHINode *Phi, BasicBlock *BB) const;
  unsigned getPhiNumber(PHINode *Phi, BasicBlock *BB);
  // getPhiIncomingFromNumber : get the phi incoming for a number returned from getPhiNumber
  std::pair<PHINode *, unsigned> getPhiIncomingFromNumber(unsigned Number);
  // createPrinterPass : get a pass to print the IR, together with the GenX
  // specific analyses
  virtual Pass *createPrinterPass(raw_ostream &O,
                                  const std::string &Banner) const {
    return createGenXGroupPrinterPass(O, Banner);
  }
  // Debug dump
  void dump();
  using llvm::Pass::print; // enables overloading of print in this class rather
                           // than override (and stops compiler warnings)
  virtual void print(raw_ostream &OS) const;

private:
  void clear();
  unsigned numberInstructionsInFunc(Function *Func, unsigned Num);
  unsigned getPhiOffset(PHINode *Phi) const;
};

void initializeGenXNumberingPass(PassRegistry &);

} // end namespace llvm
#endif //ndef GENXNUMBERING_H
