/*
 * IndvarMod.h
 *
 *  Created on: 23.4.2012
 *  Author: Robert Barucak
 *  Email: xbaruc00@stud.fit.vutbr.cz
 */

#ifndef INDVARMOD_H_
#define INDVARMOD_H_


#include "llvm/Pass.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
#include "llvm/Transforms/Utils/FunctionUtils.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Transforms/Scalar.h"
#include "llvm/Module.h"
#include "llvm/Analysis/LoopPass.h"
#include "llvm/Analysis/ScalarEvolution.h"
#include "llvm/Analysis/AliasAnalysis.h"
#include "llvm/Analysis/LoopInfo.h"
#include "llvm/Analysis/LoopDependenceAnalysis.h"
#include "llvm/Analysis/MemoryDependenceAnalysis.h"
#include "llvm/Transforms/Utils/Cloning.h"
#include "llvm/Support/IRBuilder.h"
#include "llvm/Instruction.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/ArrayRef.h"
#include <iostream>
#include <fstream>
#include <sstream>
#include <errno.h>
#include "llvm/LLVMContext.h"
#include <unistd.h>


namespace llvm {

class IndvarMod {
public:
	/**
	 * Public constructor for IndvarMod
	 */
	IndvarMod(Loop *nL,int nTripCount,Value *nIndVar);
	virtual ~IndvarMod();

	/**
	 * Start the analysis search for all loads and stores in loop
	 */
	void IndvarAnalysis();
	typedef struct MemInitx{
		Value *Origin;
		Value *Init[3];
		int Type;
	}MemInit;
	enum ModType{
	   loadMOD, //modified indvar
	   loadCONST, //constant
	   loadEQ, //equivalent to indvar
	   loadVARCONST,
	   storeMOD,
	   storeCONST,
	   storeEQ

    };
	int TripCount; /**< number of iterations*/
	int InfoCount; /**< number of vectors */
	MemInit **InfoPool; /**< array of informations about mvectors used in computation */
private:
	Loop *L; /**< processed loop */
    int InfoPoolSize; /**< size of info array */
    Value *IndVar; /**< induction variable of cycle definition aka Phinode*/
    std::vector<Value*> VEdges; /**< already visited edges of operation tree*/

    /**
     * Create info record. If indvar is found at getelementptr, no mods are there. If not, trigger topdown for
     * search of indvar
     * @param *I - load or store instruction
     * @param type - 2 if constant, 1 if load, 0 if store
     */
    void InfoGet(Value *V, int type);

    /**
     * When main store is identified code is scanned for info about loads,constants etc.
     * Scan is mandatory, because only this way we can establish link between data sources
     * in microblaze main code and picoblaze fw's.
     * @param *I first from load side
     */
    void OpScan(Instruction *I);

    /**
     * Check if node in operation tree have already been visited
     */
    bool CheckNode(Value *V);

    /**
     * Update information array, add new info record
     * @param **xNewInfo new info record
     */
    void Update(MemInit **xNewInfo);

    /**
     * Add all modifications of induction variable to mem record.
     * @param type 1 if load, 0 if store
     * @param *Input modification instruction
     * @param depth of mod instruction in chain to indvar
     * @param **NewInfo record of info data
     */
    void TopDownMod(int type, Value *Input, int depth,MemInit **NewInfo);

    /***
     * Revisit created information pool
     * place stores at the end of vector
     * in convenient order (as if generated by firmware generating backend
     * */
    void StoreCorrector();
};

}

#endif /* INDVARMOD_H_ */
