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

#include "BackendRunner.h"
#include <iosfwd>

namespace llvm {
const std::string MinBackendProlog="target triple = \"codasip\"\n";
	const std::string MinBackendEpilog="!0 = metadata !{metadata !\"float\", metadata !1}\n"
	                                   "!1 = metadata !{metadata !\"omnipotent char\", metadata !2}\n"
	                                   "!2 = metadata !{metadata !\"Simple C/C++ TBAA\", null}";
BackendRunner::BackendRunner(Function *nInput, int NTCount) {
	Input=nInput;
    TripCount=NTCount;
}

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

std::string BackendRunner::BackendAnalysis(int fw){
	fw_num=fw;
	errs()<<"-------------------------------------Backend analysis\n";
	GenerateBackendInput();
	BackendRunner::RunPhiToSelect();
	errs()<<"generated backend input on file "<<FwName <<"\n";
	return RunBackend();
}


void BackendRunner::RunPhiToSelect(){
	int PExit=256;
	std::string Command="timeout 4 ~/edkdsp/llvm_obj/Debug+Asserts+Checks/bin/opt -load=LLVMPhiToSelect.so -compact-short-evaluation autogen_tmp/"+FwName+" -o autogen_tmp/"+FwName+"_.bc";
	errs()<<"\n\n running Phitoselect \n\n\n";
	PExit = std::system(Command.c_str());
    if(PExit){
    	errs()<<"\n\n Failed PhiToSelect Execution \n\n";
    	return;
    }else{


    	Command="~/edkdsp/llvm_obj/Debug+Asserts+Checks/bin/llvm-dis autogen_tmp/" +FwName + "_.bc -o autogen_tmp/" + FwName;
        PExit=std::system(Command.c_str());
        if(PExit){
        	return;
        }
       // Command="rm autogen_tmp/"+FwName+".bc";
        PExit=std::system(Command.c_str());
        if(PExit){
          return;
        }
    }


}

std::string BackendRunner::RunBackend(){
	int BExit=256;
	int FExit=1;

	std::string Command="cp autogen_tmp/"+FwName+" autogen_tmp/__before_backend_"+FwName;
	BExit=std::system(Command.c_str());
	if(Input->getName() == "bce_caclhit_constlen_for.body"){
	   Command="autogen_tmp/link/bc2tweak.sh -n 'autogen_tmp/" + FwName +"'"; //run fw tweaker
	   BExit=std::system(Command.c_str());
	   Command="cp autogen_tmp/"+FwName+" autogen_tmp/__after_tweak_backend_"+FwName;
	   BExit=std::system(Command.c_str());
	}


	Command="~/edkdsp/llvm_obj/Debug+Asserts+Checks/bin/llc -O3 autogen_tmp/"+FwName+" -march=codasip -o autogen_tmp/"+FwName;
	BExit=std::system(Command.c_str()); //run the backend, check if generating was correct
	if(BExit!=0){
		return "";
	}
	int solve=1;
	while(solve==1){
		solve=BackendRunner::LMemConflictSolver();
		if(solve==2){
			//errs()<<"WTF\n";
			return "";
		}
	}

	BackendRunner::RunInitIncDetector();
	BackendRunner::RunSIncDetector();
	std::stringstream Convert;
	Convert<<TripCount;
	Command="autogen_tmp/link/fw_tweak.sh -i"+ Convert.str() +" -n 'autogen_tmp/" + FwName +"'"; //run fw tweaker
	FExit=std::system(Command.c_str());
	if(FExit!=0){
		return "";

	}
	return FwName;
}

int BackendRunner::LMemConflictSolver(){
	std::string tmp= "autogen_tmp/"+ FwName;
	std::ifstream NCode(tmp.c_str());
	std::string megabuff="";
	std::string incbuff="";

	std::string linebuff;
	std::string newreg="";

	BackendRunner::LMemDetector(tmp);

	std::stringstream buff;
	char xline[200];
	std::string tmp_reg="";

	int replacer = 1;
	int rerun=0;
    BackendRunner::LMemConflictDetector(&NCode, &tmp_reg,&incbuff,&megabuff);
    if(incbuff!=""){
    	rerun=1;
    	newreg=BackendRunner::LMemSelectNew();
    	if(newreg==""){
    		rerun=2;
    	}
    	//errs()<<"SELECTED NEW REG "<<newreg<<incbuff.length()<<"\n";

    	if(incbuff.length()==20){
    		incbuff.erase(3,12);
    	}
    	if(incbuff.length()==18){
    	    incbuff.erase(3,10);
    	}
    	incbuff.insert(3,newreg); //replace in init load

    	regex_t CReplace;
    	    int rv;
    	    regmatch_t CRMatch[1];
    	rv = regcomp(&CReplace, "LOAD", REG_EXTENDED);
    	    if(regexec(&CReplace, incbuff.c_str(),1,CRMatch,0)==0){
    	    	incbuff="";
    	    }

    	megabuff=megabuff+incbuff+"\n";

    	while(!NCode.eof()){
    		for(int i=0; i<200;++i){
    				xline[i]='\0';
    		}
    		NCode.getline(xline,200);
            linebuff=xline;

            if(replacer){
                BackendRunner::LMemReplaceConflict(&linebuff,tmp_reg,newreg);
                BackendRunner::LMemHaltReplace(&linebuff,tmp_reg);
            }
            megabuff=megabuff+linebuff+"\n";
    	}
    	//errs()<<megabuff;


    }

    std::string ntmp;

    if(rerun==1){
    	raw_fd_ostream *FileDump = new raw_fd_ostream(tmp.c_str(), ntmp);
    	*FileDump<<megabuff;
    	delete FileDump;

    }

	return rerun;
}

void BackendRunner::LMemReplaceConflict(std::string *linebuff, std::string search, std::string replace){
    regex_t CReplace;
    int rv;
    errs()<<"X "<<*linebuff << " Y "<< search << " Z " << replace<< "\n";
    rv = regcomp(&CReplace, search.c_str(),REG_EXTENDED);
    regmatch_t CRMatch[1];
    if(regexec(&CReplace, linebuff->c_str(), 1, CRMatch, 0)==0){
    	//errs()<<"replace valid\n";

    	linebuff->replace(CRMatch[0].rm_so,search.length(),replace);
    	//*linebuff=*linebuff; //+ " );";
errs()<<*linebuff<<"\n";
    }

    rv = regcomp(&CReplace, "LOAD", REG_EXTENDED);
    if(regexec(&CReplace, linebuff->c_str(),1,CRMatch,0)==0){
    	*linebuff="";
    }
}

int BackendRunner::LMemHaltReplace(std::string *linebuff, std::string search){
    regex_t CHalt[2];
    std::string tmp;
    int ret=1;

    int rv;
    tmp="L<"+search+"><";
    rv = regcomp(&CHalt[0],tmp.c_str() ,REG_EXTENDED);
    tmp="#S_"+search;
    rv = regcomp(&CHalt[1],tmp.c_str() ,REG_EXTENDED);
    regmatch_t CHMatch[1];
    if( regexec(&CHalt[0],linebuff->c_str(),1,CHMatch,0)==0 ){
    	ret =0;
    }
    if( regexec(&CHalt[1],linebuff->c_str(),1,CHMatch,0)==0 ){
    	ret =0;
    }


	return ret;
}

std::string BackendRunner::LMemSelectNew(){
	RegsExisting.clear();
	RegsExisting.push_back("mbank_a, 0");
	RegsExisting.push_back("mbank_a, 512");
	RegsExisting.push_back("mbank_b, 0");
	RegsExisting.push_back("mbank_b, 512");
	RegsExisting.push_back("mbank_c, 0");
	RegsExisting.push_back("mbank_c, 512");
	RegsExisting.push_back("mbank_d, 0");
	RegsExisting.push_back("mbank_d, 512");
    int found=0;
    std::string selected="";
	for(std::vector<std::string>::iterator REit=RegsExisting.begin(), REite=RegsExisting.end();REit!=REite;REit++){
        found=0;

	    for(std::vector<std::string>::iterator RUit=RegsUsed.begin(), RUite=RegsUsed.end();RUit!=RUite;RUit++){
	    	if(*RUit==*REit){
	    		found=1;
	    		break;
	    	}
	    }

	    if(!found){
	    	selected=*REit;
	    	break;
	    }
	}
    errs()<<selected<<"\n";
	return selected;
}

void BackendRunner::LMemConflictDetector( std::ifstream *NCode, std::string *tmp_reg,std::string *incbuff, std::string *megabuff){
	char xline[200];

	regex_t ILoads;
	int rv;

	rv = regcomp(&ILoads, "L<.*><" , REG_EXTENDED);
	regmatch_t ILmatches[1];

   ILoadsUsed.clear();
	while(!NCode->eof()){
		for(int i=0; i<200;++i){
			 xline[i]='\0';
		     tmp_reg->clear();
		}
		NCode->getline(xline,200);
		if(regexec(&ILoads,xline,1,ILmatches,0)==0){
			*tmp_reg=xline;
			*tmp_reg=tmp_reg->substr(ILmatches[0].rm_so+2,ILmatches[0].rm_eo - ILmatches[0].rm_so-4 );
			for(std::vector<std::string>::iterator ILit=ILoadsUsed.begin(), ILite=ILoadsUsed.end();ILit!=ILite;ILit++){
				if(*ILit==*tmp_reg){
					*incbuff=xline;
					errs()<<"FOUND CRITICAL MEMORY CONFLICT "<<*tmp_reg<<"\n" ;
					return;
				}
			}

			ILoadsUsed.push_back(*tmp_reg);
		}
		          regex_t CReplace;
		    	   // int rv;
		    	    regmatch_t CRMatch[1];
		    	rv = regcomp(&CReplace, "LOAD", REG_EXTENDED);
		    	    if(regexec(&CReplace, xline,1,CRMatch,0)==0){
		    	    	;
		    	    }else{
		*megabuff=*megabuff+xline+"\n";
		    	    }
	}
	*incbuff="";
}

void BackendRunner::LMemDetector(std::string fname){
	std::ifstream NCode(fname.c_str());
	std::string megabuff="";
	std::string incbuff="";

	std::stringstream buff;
	char xline[200];
	std::string tmp_reg;

	int rv;
	regex_t ILoads;
	regex_t CStores;
	regmatch_t ILmatches[1];
	regmatch_t CSmatches[1];
	RegsUsed.clear();
	rv = regcomp(&ILoads, "L<.*><" , REG_EXTENDED);
	rv = regcomp(&CStores, "#S_.* )", REG_EXTENDED);


	while(!NCode.eof()){
		for(int i=0; i<200;++i){
			 xline[i]='\0';
		     tmp_reg.clear();
		}
		NCode.getline(xline,200);
		if(regexec(&ILoads,xline,1,ILmatches,0)==0){
			tmp_reg=xline;
			tmp_reg=tmp_reg.substr(ILmatches[0].rm_so+2,ILmatches[0].rm_eo - ILmatches[0].rm_so-4 );
			errs()<<"\n\n\n"<<tmp_reg<<"|isolated use\n";
			RegsUsed.push_back(tmp_reg);
		}
		if(regexec(&CStores,xline,1,CSmatches,0)==0){
			tmp_reg=xline;
			tmp_reg=tmp_reg.substr(CSmatches[0].rm_so+3,CSmatches[0].rm_eo - CSmatches[0].rm_so -5);
			errs()<<"\n\n\n"<<tmp_reg<<"|isolated use\n";
			RegsUsed.push_back(tmp_reg);
		}
	}

}


void BackendRunner::RunSIncDetector(){
	std::string tmp= "autogen_tmp/"+ FwName;
	std::ifstream NCode(tmp.c_str());
	std::string megabuff="";
	std::string incbuff="";
	regmatch_t Matches[1];
	std::vector<std::string> MemSearchBuff;
	char xline[200];
    int rv,it;
    regex_t exp;
    regex_t BuffExp;
    rv = regcomp(&exp, "S<.*><",REG_EXTENDED);
    rv = regcomp(&BuffExp,"#S_.* )", REG_EXTENDED );

    it=0;
	while(!NCode.eof()){
	    for(int i=0; i<200;++i){
	        xline[i]='\0';
	    }
	    NCode.getline(xline,200);
        MemSearchBuff.push_back(xline);

	    if(regexec(&exp,xline,1,Matches, 0)==0){
	    	for(int i=0;i<10;i++){
	    		if(regexec(&BuffExp,MemSearchBuff[i].c_str(),1,Matches,0)==0){
	    			//errs()<<"FOUND FINAL STORE\n";
	    		//	errs()<<xline<<"\n";
	    			MemSearchBuff[i].replace(Matches[0].rm_so+0,1," ");
	    			MemSearchBuff[i].replace(Matches[0].rm_so+2,1,"X");
	    			MemSearchBuff[i].replace(Matches[0].rm_so+10,1,"_");
	    			MemSearchBuff[i].replace(Matches[0].rm_so+11,1,"_");
	    			incbuff=MemSearchBuff[i].substr(Matches[0].rm_so+1,Matches[0].rm_eo-Matches[0].rm_so-3);
	    			for(unsigned int j=0; j<incbuff.length();++j){
	    				incbuff[j]=toupper(incbuff[j]);
	    			}

	    			incbuff="#define " + incbuff + " 1 \n";
	    		}
	    	}

	    }


	    if(it>9){
	    	megabuff=megabuff+MemSearchBuff.front()+"\n";
	    	MemSearchBuff.erase(MemSearchBuff.begin());
	    }
        it++;
	}
	for(std::vector<std::string>::iterator It = MemSearchBuff.begin(),Ite = MemSearchBuff.end(); It!=Ite;It++){
		megabuff=megabuff+*It+"\n";
	}

	//errs()<<"commence dump\n\n"<<megabuff<<"\n\n";
	std::string ntmp;
	raw_fd_ostream *FileDump = new raw_fd_ostream(tmp.c_str(), ntmp);
	*FileDump<<megabuff;
	delete FileDump;

	tmp=tmp.substr(0,tmp.length()-2);
	tmp+="_linc_def.h";
	ntmp="ios::app";
	std::ofstream fout;
	fout.open(tmp.c_str(),std::ios::app);
	fout<<incbuff;
	fout.close();

}


void BackendRunner::RunInitIncDetector(){
	std::string tmp= "autogen_tmp/"+ FwName;
	std::ifstream NCode(tmp.c_str());
	std::string megabuff="";
	std::string incbuff="";

	std::stringstream buff;
	char xline[200];
    std::string tmp_reg;


	int rv;
	regex_t exp;
	TmpIncs.clear();
    TmpSReg.clear();
	rv = regcomp(&exp, "L<.*><" , REG_EXTENDED);
    regmatch_t matches[1];


	while(!NCode.eof()){
		for(int i=0; i<200;++i){
		    xline[i]='\0';
		    tmp_reg.clear();
		}

	    NCode.getline(xline,200);
	    if(regexec(&exp,xline,1,matches,0)==0){
		    tmp_reg=xline;
		    tmp_reg=tmp_reg.substr(matches[0].rm_so,matches[0].rm_eo - matches[0].rm_so );

		    tmp_reg[1]='_';
		    tmp_reg[tmp_reg.length()-1]='\\';
		    tmp_reg[tmp_reg.length()-2]=' ';
		    tmp_reg+=')';
		    tmp_reg='#'+tmp_reg;
		    BackendRunner::AddTmpReg( tmp_reg);
	    }
        std::vector<std::vector<regex_t **>::iterator> ToDelete;

	    for(std::vector<regex_t **>::iterator RegIt = TmpSReg.begin(), RegIte = TmpSReg.end(); RegIt!=RegIte;++RegIt){
	    	if(regexec((*RegIt)[1],xline,1,matches,0)==0){
	    		ToDelete.push_back(RegIt);
	    		continue;
	    	}
	    }

	    for(std::vector<std::vector<regex_t **>::iterator>::iterator RegDIt = ToDelete.begin(), RegDIte = ToDelete.end(); RegDIt!=RegDIte;++RegDIt){
	    	TmpSReg.erase(*RegDIt);
	    }

	    for(std::vector<regex_t **>::iterator RegIt = TmpSReg.begin(), RegIte = TmpSReg.end(); RegIt!=RegIte;++RegIt){
	    	if(regexec((*RegIt)[0],xline,1,matches,0)==0){

	    		xline[matches[0].rm_so+0]=' ';
	    		xline[matches[0].rm_so+2]='X';
	    		xline[matches[0].rm_so+10]='_';
	    		xline[matches[0].rm_so+11]='_';
	    		tmp_reg=xline;
	    		tmp_reg=tmp_reg.substr(matches[0].rm_so,matches[0].rm_eo - matches[0].rm_so -1 );
	    		//errs()<<xline<<"GOT LOAD\n";
	    		for(unsigned int i=0;i<tmp_reg.length()-4;i++){
	    			tmp_reg[i]=toupper(tmp_reg[i]);
	    		}

	    		int IsThere=0;
	    		for(std::vector<std::string>::iterator IncIt = TmpIncs.begin(), IncIte = TmpIncs.end(); IncIt!=IncIte;++IncIt){
	    			if(*IncIt==tmp_reg){
	    				IsThere=1;
	    			}
	    		}
	    		if(!IsThere){
	    			TmpIncs.push_back(tmp_reg);
	    		    tmp_reg= "#define "+tmp_reg + "1";
	    		    incbuff+=tmp_reg+"\n";
	    		}

	    		//ToDelete.push_back(RegIt);
	    	}
	    }







	    megabuff=megabuff+xline+'\n';
	    //errs()<<xline<<"|NCODE\n";
	}

	std::string ntmp;
	raw_fd_ostream *FileDump = new raw_fd_ostream(tmp.c_str(), ntmp);
	//errs()<<"FILENAME:"<<tmp<<"\n";
	*FileDump<<megabuff;
	delete FileDump;

	tmp=tmp.substr(0,tmp.length()-2);
	tmp+="_linc_def.h";
	FileDump = new raw_fd_ostream(tmp.c_str(), ntmp);
    *FileDump<<incbuff;
	delete FileDump;
}

void BackendRunner::AddTmpReg(std::string Reg){
	regex_t **NewReg;
	NewReg=new regex_t*[2];
	 NewReg[0]= new regex_t;
	 NewReg[1]= new regex_t;
	//regex_t *NewSReg = new regex_t;
	int rv;
	//errs()<<"NEW            "<<Reg<<"\n";
	rv = regcomp(NewReg[0], Reg.c_str() , REG_EXTENDED);
	Reg[1]='S';
	rv = regcomp(NewReg[1], Reg.c_str() , REG_EXTENDED);

	TmpSReg.push_back(NewReg);
	//TmpReg.push_back(NewReg);
}


void BackendRunner::GenerateBackendInput(){
	 std::string tmp;
	 std::string fname;
	 std::string copyname;
	 std::stringstream convert;
	 LoopPulverizator();
	 convert<<fw_num;
	 FwName="fw_" + convert.str() + "_";
	 FwName+= BEInput->getNameStr() + ".c";
	 fname="autogen_tmp/"+FwName;
	 raw_fd_ostream *FunctionDump = new raw_fd_ostream(fname.c_str(), tmp);
	 *FunctionDump<<"; ModuleID = '"<<BEInput->getNameStr().c_str()<<".bc'\n";
	 *FunctionDump<<MinBackendProlog<<*BEInput<<"\n"<<MinBackendEpilog;
	 delete FunctionDump; //dump function with prolog and epilog

	 copyname=BEInput->getNameStr()+"_copy";
	 fname="autogen_tmp/"+copyname;
	 FunctionDump = new raw_fd_ostream(fname.c_str(), tmp);
	 *FunctionDump<<"; ModuleID = '"<<BEInput->getNameStr().c_str()<<".bc'\n";
	 *FunctionDump<<MinBackendProlog<<*BEInput<<"\n"<<MinBackendEpilog;
	 delete FunctionDump;
	 BEInput->deleteBody();
}

void BackendRunner::LoopPulverizator(){
	Function *ULFunc=llvm::CloneFunction(Input);
	ULFunc->setName(Input->getNameStr() + "_clone");
	ULFunc->setLinkage(GlobalValue::InternalLinkage);
	CentralNode=NULL;
	//ULFunc->viewCFG();
	for(llvm::Function::arg_iterator FLI = ULFunc->getArgumentList().begin(),FLIE = ULFunc->getArgumentList().end(); FLI!=FLIE;++FLI){ //loop extractor determined all data pods used in loop
	    //now its time to trace then, de-vectorize them and then destroy whats left of the loop
	    //because of loop extractor param packing feature, there is only one expected with multiple uses- each use is one "unpack"
	    //It is possible for param to not be linked with load (classic variable). If so, chain detector must not be turned on.
		if(!dyn_cast<Value>(FLI)->getType()->isFloatTy())
		    ChainDetector(FLI,0);
	}

	BackendRunner::KillIndMods();
	BackendRunner::BreakLoop();
	//ULFunc->viewCFG();

	BEInput=ULFunc;

}

bool BackendRunner::ChainDetector(Value *UV,int LoadLvl){
    //iterate through use-def chain until we get from parameter pack all the way to "load" of useful data
	//then strike and take down the loop- destroy iteration over array
	for(Value::use_iterator UVI = UV->use_begin(),UVIe = UV->use_end(); UVI!=UVIe; ++UVI){
		llvm::Instruction *Cmp= dyn_cast<Instruction>(*UVI);

		if(Cmp->getOpcode()==Instruction::Load|| Cmp->getOpcode()==Instruction::Store){
			//desired instruction is 1 load away, first one is unpacking the parameter, second one is the load we are looking for
			if(LoadLvl==0)
			    return false;
			LoadLvl++;

		}

		//if load is next in use-def, destroy connection to indvar
		//by replacing indvar related stuff with constant,
		//then go after whats left of the indvar
		if(!ChainDetector(dyn_cast<Value>(*UVI),LoadLvl)){
			llvm::Value *ConstVal = ConstantInt::get(Type::getInt32Ty(getGlobalContext()), 0);
			//errs()<<*Cmp<<"marked\n";
			BackendRunner::IndvarMarker(Cmp->getOperand(1));
			BackendRunner::MarkForKill(Cmp->getOperand(1));
			Cmp->setOperand(1,ConstVal);
		}
	}
	return true;
}

void BackendRunner::IndvarMarker(Value *Input){
	if(!(dyn_cast<Instruction>(Input))){
			return;
	}
	Instruction *Inspect= dyn_cast<Instruction>(Input);
	if(isa<PHINode>(Inspect)){
		CentralNode=dyn_cast<PHINode>(Inspect);
		return;
	}
	for(llvm::Instruction::op_iterator OpI=Inspect->op_begin(),OpIe = Inspect->op_end(); OpI!=OpIe; ++OpI){
		if(isa<Instruction>(*OpI) ){
			BackendRunner::MarkForKill(*OpI);
			BackendRunner::IndvarMarker(*OpI);
			llvm::Value *ConstVal = ConstantInt::get(Type::getInt32Ty(getGlobalContext()), 0);
			OpI->set(ConstVal);
		}
	}
}

void BackendRunner::MarkForKill(Value *Test){
	for(std::vector<Value *>::iterator ValIt = ToKill.begin(), ValIte = ToKill.end(); ValIt!=ValIte;++ValIt){
		if(*ValIt==Test){
			return;
		}
	}
	ToKill.push_back(Test); //add to tokill only if its not already there, otherwise there can be bad pointer in processing
}

void BackendRunner::KillIndMods(){
	std::vector<Value *> *ItOv;
	std::vector<Value *> Optional;
	std::vector<Value *> tmp;
	ItOv=&ToKill;
	while(ItOv!=NULL){
	    for(std::vector<Value *>::iterator ValIt = ItOv->begin(); ValIt!=ItOv->end(); ++ValIt){ //run rkill over tokill vector
		    BackendRunner::RKill(*ValIt,&Optional);
	    }
	    ItOv=NULL;
	    if(!Optional.empty()){  //TODO need to check if this work
	    	tmp=Optional;
	    	Optional.clear();
	    	ItOv=&tmp;
	    }
	}
}

void BackendRunner::RKill(Value *Test, std::vector<Value *> *tmp){
	if(!(dyn_cast<Instruction>(Test))){
		return;
	}

	Instruction *Inspect= dyn_cast<Instruction>(Test);
	if(isa<PHINode>(Inspect)){
		CentralNode=dyn_cast<PHINode>(Inspect); //back off if this is phinode!, branch must be corrected or def will be lost before use
		return;
	}
	for(llvm::Instruction::op_iterator OpI=Inspect->op_begin(),OpIe = Inspect->op_end(); OpI!=OpIe; ++OpI){
		if(isa<Instruction>(*OpI) ){
			tmp->push_back(*OpI); //if more mods are in the way up to phinode, add them to tokill list
		}
	}
	Inspect->eraseFromParent();
}

void BackendRunner::BreakLoop(){
	if(CentralNode==NULL){

		return;
	}
	unsigned int FinNum= CentralNode->getNumIncomingValues();
	for(unsigned int i=0;i<FinNum;++i){
		Value *PosIndvar=CentralNode->getIncomingValue(0);
		if(isa<Instruction>(PosIndvar)){
			BackendRunner::BranchCorrector(PosIndvar); //find branch which ensures jumping back to Phinode
		}
		CentralNode->removeIncomingValue(unsigned(0),true);
	}
}

void BackendRunner::BranchCorrector(Value *Input){
	if(isa<Instruction>(Input)){
		Instruction *Tmp=dyn_cast<Instruction>(Input);
		if(isa<BranchInst>(Tmp)){
			BranchInst *Xtmp = dyn_cast<BranchInst>(Tmp);
			if(Xtmp->isConditional()){ //delete main branch ending the loop
				BackendRunner::BranchReset(Xtmp);
			}
			return;
		}
		for(llvm::Value::use_iterator OpI=Tmp->use_begin(),OpIe = Tmp->use_end(); OpI!=OpIe; ++OpI){
			if(isa<Instruction>(*OpI) && !isa<PHINode>(*OpI)){
				BackendRunner::BranchCorrector(*OpI);
			}
		}
		Tmp->dropAllReferences(); //drop references to old branch
		Tmp->removeFromParent();
	}
}

void BackendRunner::BranchReset(BranchInst *Input){
	BasicBlock *RetB=NULL;
	BasicBlock *FinalDest=NULL;
	for(llvm::Instruction::op_iterator OpI=Input->op_begin(),OpIe = Input->op_end(); OpI!=OpIe; ++OpI){
		if((RetB=dyn_cast<BasicBlock>(*OpI))){ //find branch to exiting block
			TerminatorInst *PosRet=RetB->getTerminator();
			if(isa<ReturnInst>(PosRet)){
				FinalDest=RetB;
			}
		}
	}
	if(FinalDest==NULL){
		return;
	}
	static IRBuilder<> Builder(getGlobalContext()); //builder for new branch
	BranchInst *ReBranched;
	ReBranched=Builder.CreateBr(FinalDest);
	ReBranched->insertBefore(Input);
	Input->dropAllReferences();
	Input->removeFromParent();
}

}
