/*
 * LoopCorrect.cpp
 *
 *  Created on: 29.2.2012
 *  Author: Robert Barucak
 *  Email: xbaruc00@stud.fit.vutbr.cz
 */

#include "LoopCorrect.h"

namespace llvm {

//loop checking will take place over loop given in constructor
LoopCorrect::LoopCorrect(Loop *nL,Loop::block_iterator nLit,std::vector<BasicBlock*> nForbidenBlocks) {
	L=nL;
    Lit=nLit;
    ForbidenBlocks=nForbidenBlocks;
}

LoopCorrect::~LoopCorrect() {
	// TODO Auto-generated destructor stub
}

bool LoopCorrect::IsLoopCorrect(Value **IVStartValue, Value **IVExitValue, PHINode **IndVar,int *TripCount){
	if(!InputBlockCorrect())
		return false;
	BasicBlock *ExitingBlock=L->getExitingBlock();
    if (!ExitingBlock)
    	return false;
	if (!L->getSubLoops().empty()) //no subloops can be inside
		return false;
    if (!L->isLoopSimplifyForm()) //loop must by in simplify form
		return false;

    *IndVar=L->getCanonicalInductionVariable(); //canonical index variable- needed in data settings
    if(IndVar==NULL)
        return false;
    ICmpInst *ExitCondition;
    BranchInst *EBR = dyn_cast<BranchInst>(ExitingBlock->getTerminator()); //terminator of exiting block
    if (!EBR)
    	return false;
    ExitCondition = dyn_cast<ICmpInst>(EBR->getCondition()); //without available exit condition there is nothing to analyze
    if (!ExitCondition)
    	return false;
    *IVExitValue = ExitCondition->getOperand(1); //exit value and trip count are needed in analysis
    if(llvm::ConstantInt *CI=dyn_cast<ConstantInt>(*IVExitValue)){
        *TripCount=CI->getSExtValue();
    }else
    	return false;

   // unsigned LoopDepth=L->getLoopDepth(); //Loop depth must be 1, because of loop function generator - it will fall on assert other way
    //if(LoopDepth>1)
    //	return false;     EDIT: now there is no need for maximal depth check. If inner loop is modified, parent is thrown away - it cannot be used anyway!

    if(IsMinimalWrapper())
    	return false;


	return true;
}

bool LoopCorrect::IsMinimalWrapper(){
	bool ShouldExtractLoop = true;
    // Extract the loop if the entry block isn't only a branch to loop header
    BasicBlock *EntryBI = &L->getHeader()->getParent()->getEntryBlock();
    for(BasicBlock::iterator BI = (EntryBI)->begin(), BE = (EntryBI)->end(); BI != BE; ++BI){
        if(!isa<BranchInst>(BI) && !isa<GetElementPtrInst>(BI) && !isa<LoadInst>(BI)){
            return false;
        }
    }
        // Check to see if any exits from the loop are more than just blocks with one return instruction
    SmallVector<BasicBlock*, 8> ExitBlocks;
    L->getExitBlocks(ExitBlocks);
    for (unsigned i = 0, e = ExitBlocks.size(); i != e; ++i){
    	for(BasicBlock::iterator BI = (ExitBlocks[i])->begin(), BE = (ExitBlocks[i])->end(); BI != BE; ++BI){
    		if(!isa<ReturnInst>(BI) ){
    		    return false;
    		}
    	}
    }

    return ShouldExtractLoop;
}

bool LoopCorrect::InputBlockCorrect(){
	for(;Lit!=L->block_end();Lit++){
		BasicBlock* tmp1=*Lit;
		std::vector<BasicBlock*>::iterator itr;
		for ( itr = ForbidenBlocks.begin(); itr != ForbidenBlocks.end(); ++itr ){ //if loop was already altered by acc, return false(segfault imminent)
			BasicBlock* tmp2=*itr;
			if(tmp1==tmp2){
				return false;
			}
		}
	}
	return true;
}

void LoopCorrect::ParentDrop(LPPassManager &LPM){
	if(L->getParentLoop()!=NULL){
		LoopCorrect::RParentDropper(L->getParentLoop(),LPM);
		LPM.deleteLoopFromQueue(L->getParentLoop());
	}
}

void LoopCorrect::RParentDropper(Loop *Dropped,LPPassManager &LPM){
	if(Dropped->getParentLoop()!=NULL){
		LoopCorrect::RParentDropper(Dropped->getParentLoop(),LPM);
		LPM.deleteLoopFromQueue(Dropped->getParentLoop());
	}
}

}
