#include "leak_detector.h"

#include "dvm.h"
#include "acc_analyzer.h"
#include "calls.h"
#include <fstream>
#include <stdint.h>

using std::string;
using std::vector;
using std::map;
using std::list;
using std::make_pair;
using std::set;
using std::pair;

#if __SPF
using std::wstring;
#include "../_src/Utils/AstWrapper.h"
#include "../_src/Utils/utils.h"
#include "../_src/Utils/errors.h"

static pair<wstring, string> getText(const char *s, const wchar_t *s1, const char *t, int num, SgStatement *stmt, int &line)
{
    pair<wstring, string> ret;

    wchar_t bufW[1024];
#if _WIN32
    swprintf(bufW, s1, to_wstring(t).c_str());
#else
    swprintf(bufW, 1024, s1, to_wstring(t).c_str());
#endif
    ret.first = bufW;

    char buf[1024];
    sprintf(buf, s, t);
    ret.second = buf;

    line = stmt->lineNumber();
    if (line == 0)
    {
        line = 1;
        if (stmt->variant() == DVM_PARALLEL_ON_DIR)
        {
            line = stmt->lexNext()->lineNumber();
            ret.first += RR158_1;
            ret.second += " for this loop";
        }
    }

    if (stmt->variant() == SPF_ANALYSIS_DIR)
    {
        ret.first += RR158_1;
        ret.second += " for this loop";
    }

    return ret;
}

static inline bool ifVarIsLoopSymb(SgStatement *stmt, const string symb)
{    
    bool ret = false;
    if (stmt == NULL)
        return ret;

    int var = stmt->variant();    
    if (var == SPF_ANALYSIS_DIR || var == SPF_PARALLEL_DIR || var == SPF_TRANSFORM_DIR || var == SPF_PARALLEL_REG_DIR || var == SPF_END_PARALLEL_REG_DIR)
        stmt = stmt->lexNext();
        
    SgForStmt *forS = isSgForStmt(stmt);
    if (forS)
    {
        SgStatement *end = forS->lastNodeOfStmt();
        for (; stmt != end && !ret; stmt = stmt->lexNext())
            if (stmt->variant() == FOR_NODE)
                if (isSgForStmt(stmt)->symbol()->identifier() == symb)
                    ret = true;
    }

    return ret;
}


template<typename fillType> void fillPrivatesFromComment(Statement *st, std::set<fillType> &privates, int type = -1);

inline void Warning(const char *s, const wchar_t *s1, const char *t, int num, SgStatement *stmt)
{
    //TODO: is it correct?
    if (stmt == NULL)
        return;

    if (num == PRIVATE_ANALYSIS_REMOVE_VAR)
    {
        SgStatement *found = SgStatement::getStatementByFileAndLine(string(stmt->fileName()), stmt->lineNumber());
        if (found != NULL)
        {
            if (ifVarIsLoopSymb(found, t))
                return;
        }

        set<string> privates;
        fillPrivatesFromComment(new Statement(stmt), privates);
        if (privates.find(t) != privates.end())
            return;
    }

    
    int line;
    auto retVal = getText(s, s1, t, num, stmt, line);
    printLowLevelWarnings(stmt->fileName(), line, retVal.first.c_str(), retVal.second.c_str(), 1029);
}

inline void Note(const char *s, const wchar_t *s1, const char *t, int num, SgStatement *stmt)
{    
    int line;
    auto retVal = getText(s, s1, t, num, stmt, line);
    printLowLevelNote(stmt->fileName(), line, retVal.first.c_str(), retVal.second.c_str(), 1030);
}
#endif

// local functions
static ControlFlowItem* getControlFlowList(SgStatement*, SgStatement*, ControlFlowItem**, SgStatement**, doLoops*, CallData*, CommonData*);
static ControlFlowItem* processOneStatement(SgStatement** stmt, ControlFlowItem** pred, ControlFlowItem **list, ControlFlowItem* oldcur, doLoops*, CallData*, CommonData*);
static ControlFlowItem* switchItem(SgStatement* stmt, ControlFlowItem* empty, SgStatement** lastAnStmt, doLoops* loops, CallData* calls, CommonData*);
static ControlFlowItem* ifItem(SgStatement*, ControlFlowItem*, SgStatement** lastAnStmt, doLoops* loops, bool ins, CallData*, CommonData*);
static void setLeaders(ControlFlowItem*);
static void clearList(ControlFlowItem*);
static void fillLabelJumps(ControlFlowItem*);
static SgExpression* GetProcedureArgument(bool isF, void* f, int i);
static int GetNumberOfArguments(bool isF, void* f);
#if ACCAN_DEBUG
static void printControlFlowList(ControlFlowItem*, ControlFlowItem* last = NULL);
#endif

//static ControlFlowGraph* GetControlFlowGraphWithCalls(bool, SgStatement*, CallData*, CommonData*);
//static void FillCFGSets(ControlFlowGraph*);
static void FillPrivates(ControlFlowGraph*);
static ControlFlowItem* AddFunctionCalls(SgStatement*, CallData*, ControlFlowItem**, CommonData*);

const char* is_correct = NULL;
const char* failed_proc_name = NULL;
static PrivateDelayedItem* privateDelayedList = NULL;
static AnalysedCallsList* currentProcedure = NULL;
static AnalysedCallsList* mainProcedure = NULL;
static DoLoopDataList* doLoopList = NULL;
static CommonData* pCommons;
static CallData* pCalls;

int total_privates = 0;
int total_pl = 0;

static const IntrinsicSubroutineData intrinsicData[] = {
    {"date_and_time", 4, { {-1, "date", INTRINSIC_OUT}, {-1, "time", INTRINSIC_OUT }, {-1, "zone", INTRINSIC_OUT }, {-1, "values", INTRINSIC_OUT } } },
    {"mod", 2, { {1, NULL, INTRINSIC_IN}, {2, NULL, INTRINSIC_IN} } },
    {"dvtime", 0, {}},
    {"abs", 1, { {1, NULL, INTRINSIC_IN} } },
    {"max", 2, { {1, NULL, INTRINSIC_IN}, {2, NULL, INTRINSIC_IN} } },
    {"min", 2, { {1, NULL, INTRINSIC_IN}, {2, NULL, INTRINSIC_IN} } },
    {"wtime", 1, { {1, NULL, INTRINSIC_IN} } },
    {"dble", 1, { {1, NULL, INTRINSIC_IN } } },
    {"dabs", 1, { {1, NULL, INTRINSIC_IN } } },
    {"dmax1", 2, { {1, NULL, INTRINSIC_IN}, {2, NULL, INTRINSIC_IN } } },
    {"dmin1", 2, { {1, NULL, INTRINSIC_IN}, {2, NULL, INTRINSIC_IN } } },
    {"dsqrt", 1, { {1, NULL, INTRINSIC_IN} } },
    {"dcos", 1, { {1, NULL, INTRINSIC_IN} } },
    {"datan2", 2, { {1, NULL, INTRINSIC_IN}, {2, NULL, INTRINSIC_IN} } },
    {"dsign", 2, { {1, NULL, INTRINSIC_IN}, {2, NULL, INTRINSIC_IN} } },
    {"dlog", 1, { {1, NULL, INTRINSIC_IN} } },
    {"dexp", 1, { {1, NULL, INTRINSIC_IN} } },
    {"omp_get_wtime", 0, {}},
    {"sqrt", 1, { {1, NULL, INTRINSIC_IN} } },
    {"int", 1, { {1, NULL, INTRINSIC_IN} } },
    {"iabs", 1, { {1, NULL, INTRINSIC_IN} } },
    {"fnpr", 4, { {1, NULL, INTRINSIC_IN},{ 2, NULL, INTRINSIC_IN },{ 3, NULL, INTRINSIC_IN },{ 4, NULL, INTRINSIC_IN } } },
    {"isnan", 1, { {1, NULL, INTRINSIC_IN } } }
};

//TODO: it does not work
//static map<SgStatement*, tuple<ControlFlowGraph*, CallData*, CommonData*>> CFG_cache;


static bool isIntrinsicFunctionNameACC(char* name)
{
#if USE_INTRINSIC_DVM_LIST
    return isIntrinsicFunctionName(name);
#else
    return false;
#endif
}

int SwitchFile(int file_id)
{
    if (file_id == current_file_id || file_id == -1)
        return file_id;
    int stored_file_id = current_file_id;
    current_file_id = file_id;
    current_file = &(CurrentProject->file(current_file_id));
    return stored_file_id;
}

SgStatement * lastStmtOfDoACC(SgStatement *stdo)
{
    // is a copied function
    SgStatement *st;
    // second version  (change 04.03.08) 
    st = stdo;
RE: st = st->lastNodeOfStmt();
    if ((st->variant() == FOR_NODE) || (st->variant() == WHILE_NODE))
        goto RE;

    else if (st->variant() == LOGIF_NODE)
        return(st->lexNext());

    else
        return(st);

}

#ifdef __SPF
bool IsPureProcedureACC(SgSymbol* s)
#else
static bool IsPureProcedureACC(SgSymbol* s)
#endif
{
    // is a copied function
    SgSymbol *shedr = NULL;

    shedr = GetProcedureHeaderSymbol(s);
    if (shedr)
        return(shedr->attributes() & PURE_BIT);
    else
        return 0;
}

static bool IsUserFunctionACC(SgSymbol* s)
{
    // is a copied function
    return(s->attributes() & USER_PROCEDURE_BIT);
}

static const IntrinsicSubroutineData* IsAnIntrinsicSubroutine(const char* name)
{
    for (int i = 0; i < sizeof(intrinsicData) / sizeof(intrinsicData[0]); i++)
        if (strcmp(name, intrinsicData[i].name) == 0)
            return &(intrinsicData[i]);
    return NULL;
}

static SgExpression* CheckIntrinsicParameterFlag(const char* name, int arg, SgExpression* p, unsigned char flag)
{
    const IntrinsicSubroutineData* info = IsAnIntrinsicSubroutine(name);
    if (!info)
        return NULL; //better avoid this
    for (int i = 0; i < info->args; i++) 
    {
        const IntrinsicParameterData* pd = &(info->parameters[i]);
        if (pd->index == arg + 1)
            return (pd->status & flag) != 0 ? p : NULL;

        SgKeywordArgExp* kw = isSgKeywordArgExp(p);
        if (kw) 
        {
            SgExpression* a = kw->arg();
            SgExpression* val = kw->value();
            if (pd->name && strcmp(a->unparse(), pd->name) == 0)
                return (pd->status & flag) != 0 ? val : NULL;
        }
    }
    return NULL;
}
/*
//For parameters replacements in expressions
//#ifdef __SPF

VarsKeeper varsKeeper;

SgExpression* GetValueOfVar(SgExpression* var)
{
    return varsKeeper.GetValueOfVar(var);
}

void VarsKeeper::GatherVars(SgStatement* start)
{
    pCommons = &(data->commons);
    pCalls = &(data->calls);
    currentProcedure = data->calls.AddHeader(start, false, start->symbol());
    mainProcedure = currentProcedure;
    //stage 1: preparing graph data
    data->graph = GetControlFlowGraphWithCalls(true, start, &(data->calls), &(data->commons));
    data->calls.AssociateGraphWithHeader(start, data->graph);
    data->commons.MarkEndOfCommon(currentProcedure);
    //calls.printControlFlows();
    //stage 2: data flow analysis
    FillCFGSets(data->graph);
    //stage 3: fulfilling loop data
    FillPrivates(data->graph);

    if (privateDelayedList)
            delete privateDelayedList;
        privateDelayedList = NULL;
}

SgExpression* VarsKeeper::GetValueOfVar(SgExpression* var)
{
    FuncData* curData = data;
}

//#endif
*/



void SetUpVars(CommonData* commons, CallData* calls, AnalysedCallsList* m, DoLoopDataList* list)
{
    pCommons = commons;
    pCalls = calls;
    currentProcedure = m;
    mainProcedure = currentProcedure;
    doLoopList = list;
}

AnalysedCallsList* GetCurrentProcedure()
{
    return currentProcedure;
}
//interprocedural analysis, called for main procedure
void Private_Vars_Analyzer(SgStatement* start)
{
#ifndef __SPF 
    if (!options.isOn(PRIVATE_ANALYSIS)) {
        return;
    }
#endif
    CallData calls;
    CommonData commons;
    DoLoopDataList doloopList;
    SetUpVars(&commons, &calls, calls.AddHeader(start, false, start->symbol(), current_file_id), &doloopList);

    //stage 1: preparing graph data
    ControlFlowGraph* CGraph = GetControlFlowGraphWithCalls(true, start, &calls, &commons);
    calls.AssociateGraphWithHeader(start, CGraph);
    commons.MarkEndOfCommon(currentProcedure);
        
    currentProcedure->graph->getPrivate();
#if ACCAN_DEBUG
    calls.printControlFlows();
#endif
    //stage 2: data flow analysis
    FillCFGSets(CGraph);
    //stage 3: fulfilling loop data
    FillPrivates(CGraph);

    //test: graphvis
    /*std::fstream fs;
    fs.open("graph_old.txt", std::fstream::out);
    fs << CGraph->GetVisualGraph(&calls);
    fs.close();*/

#if !__SPF
    delete CGraph;
#endif

    if (privateDelayedList)
        delete privateDelayedList;
    privateDelayedList = NULL;
}

CallData::~CallData()
{
#if __SPF
    removeFromCollection(this);
    return;
#endif
    /*
    for (AnalysedCallsList* l = calls_list; l != NULL;) 
    {
        if (!l->isIntrinsic && l->graph)
        {
            if (l->graph->RemoveRef() && !l->graph->IsMain())
            {
                delete l->graph;
                l->graph = NULL;
            }
        }
        AnalysedCallsList *temp = l;
        l = l->next;
        delete temp;
        temp = NULL;
    }*/
}

CommonData::~CommonData()
{
#if __SPF
    removeFromCollection(this);
    return;
#endif
    for (CommonDataItem* i = list; i != NULL;) {
        for (CommonVarInfo* info = i->info; info != NULL;) {
            CommonVarInfo* t = info;
            info = info->next;
            delete t;
        }
        CommonDataItem* tp = i;
        i = i->next;
        delete tp;
    }
}

ControlFlowGraph::~ControlFlowGraph()
{
#if __SPF
    removeFromCollection(this);
    return;
#endif
    while (common_def != NULL) 
    {
        CommonVarSet* t = common_def;
        common_def = common_def->next;
        delete t;
    }
    while (common_use != NULL) 
    {
        CommonVarSet* t = common_use;
        common_use = common_use->next;
        delete t;
    }

    if (def)
        delete def;    

    if (use)
        delete use;   

    if (!temp && pri)
        delete pri;    

    for (CBasicBlock *bb = first; bb != NULL;) 
    {
        CBasicBlock *tmp = bb;
        bb = bb->getLexNext();
            
        delete tmp;
        tmp = NULL;
    }
}

CBasicBlock::~CBasicBlock()
{
#if __SPF
    removeFromCollection(this);
    return;
#endif    

    CommonVarSet* d = getCommonDef();
    while (d != NULL) 
    {
        CommonVarSet* t = d;
        d = d->next;
        delete t;
    }

    d = getCommonUse();
    while (d != NULL) 
    {
        CommonVarSet* t = d;
        d = d->next;
        delete t;
    }

    for (BasicBlockItem* bbi = prev; bbi != NULL;)
    {
        BasicBlockItem *tmp = bbi;
        bbi = bbi->next;
        delete tmp;
        tmp = NULL;
    }

    for (BasicBlockItem *bbi = succ; bbi != NULL;)
    {
        BasicBlockItem *tmp = bbi;
        bbi = bbi->next;
        delete tmp;
        tmp = NULL;
    }

    if (def)
        delete def;    

    if (use)
        delete use;    

    if (old_mrd_out)
        delete old_mrd_out;
    
    if (old_mrd_in)
        delete old_mrd_in;
    
    if (mrd_in)
        delete mrd_in;
    
    if (mrd_out)
        delete mrd_out;
    
    if (old_lv_out)
        delete old_lv_out;
    
    if (old_lv_in)
        delete old_lv_in;
    
    if (lv_in)
        delete lv_in;
    
    if (lv_out)
        delete lv_out;
}

doLoops::~doLoops()
{
#if __SPF
    removeFromCollection(this);
    return;
#endif
    for (doLoopItem *it = first; it != NULL; ) 
    {
        doLoopItem *tmp = it;
        it = it->getNext();
        delete tmp;
    }
}

PrivateDelayedItem::~PrivateDelayedItem()
{
#if __SPF
    removeFromCollection(this);
    return;
#endif
    if (delay)
        delete delay;
    if (next)
        delete next;    
}

VarSet::~VarSet()
{
#if __SPF
    removeFromCollection(this);
#endif
    for (VarItem* it = list; it != NULL;) 
    {
        VarItem* tmp = it;
        it = it->next;
        if (tmp->var)
            if (tmp->var->RemoveReference())
                delete tmp->var;
        delete tmp;
    }
}

CommonVarSet::CommonVarSet(const CommonVarSet& c)
{    
    cvd = c.cvd;
    if (c.next)
        next = new CommonVarSet(*c.next);
    else
        next = NULL;

#if __SPF
    addToCollection(__LINE__, __FILE__, this, 22);
#endif
}

std::string ControlFlowGraph::GetVisualGraph(CallData* calls)
{
    std::string result;
    result += "digraph ";
    char tmp[512];
    AnalysedCallsList* cd = calls->GetDataForGraph(this);
    //if (cd == NULL || cd->header == NULL)
        sprintf(tmp, "g_%llx", (uintptr_t)this);
    //else
    //    sprintf(tmp, "g_%500s", cd->header->symbol());
    result += tmp;
    result += "{ \n";
    for (CBasicBlock* b = this->first; b != NULL; b = b->getLexNext()) {
        if (!b->IsEmptyBlock()) {
            result += '\t' + b->GetGraphVisDescription() + "[shape=box,label=\"";
            result += b->GetGraphVisData() + "\"];\n";
        }
    }
    for (CBasicBlock* b = first; b != NULL; b = b->getLexNext()) {
        if (!b->IsEmptyBlock())
            result += b->GetEdgesForBlock(b->GetGraphVisDescription(), true, "");
    }
    result += '}';
    ResetDrawnStatusForAllItems();
    return result;
}

void ControlFlowGraph::ResetDrawnStatusForAllItems() {
    for (CBasicBlock* b = first; b != NULL; b = b->getLexNext()) {
        for (ControlFlowItem* it = b->getStart(); it != NULL && (it->isLeader() == false || it == b->getStart()); it = it->getNext()) {
            it->ResetDrawnStatus();
        }
    }
}

std::string GetConditionWithLineNumber(ControlFlowItem* eit)
{
    std::string res;
    if (eit->getOriginalStatement()) {
        char tmp[16];
        sprintf(tmp, "%d: ", eit->getOriginalStatement()->lineNumber());
        res = tmp;
    }
    return res + eit->getExpression()->unparse();
}

std::string GetActualCondition(ControlFlowItem** pItem) {
    std::string res = "";
    ControlFlowItem* eit = *pItem;
    while (true) 
    {
        if (eit == NULL || eit->getJump() != NULL || eit->getStatement() != NULL) 
        {
            if (eit && eit->getJump() != NULL) 
            {
                if (eit->getExpression() != NULL) 
                {
                    *pItem = eit;
                    return GetConditionWithLineNumber(eit);
                }
                else 
                {
                    *pItem = NULL;
                    return res;
                }
                break;
            }
            *pItem = NULL;
            return res;
        }
        eit = eit->GetPrev();
    }
    return res;
}

std::string CBasicBlock::GetEdgesForBlock(std::string name, bool original, std::string modifier)
{
    std::string result;
    for (BasicBlockItem* it = getSucc(); it != NULL; it = it->next) {
        if (it->drawn)
            continue;
        it->drawn = true;
        char lo = original;
        std::string cond;
        ControlFlowItem* eit = NULL;
        bool pf = false;
        if (it->jmp != NULL) {
            if (it->jmp->getExpression() != NULL) {
                eit = it->jmp;
                cond = GetConditionWithLineNumber(eit);
            }
            else {
                pf = true;
                eit = it->jmp->GetPrev();
                cond = GetActualCondition(&eit);
            }
        }
        if (eit && eit->GetFriend()) {
            lo = false;
            eit = eit->GetFriend();
        }
        if (!it->block->IsEmptyBlock() || cond.length() != 0) {
            if (cond.length() != 0 && eit && !pf){
                char tmp[32];
                sprintf(tmp, "c_%llx", (uintptr_t)eit);
                if (!eit->IsDrawn()) {
                    result += '\t';
                    result += tmp;
                    result += "[shape=diamond,label=\"";
                    result += cond;
                    result += "\"];\n";
                }
                if (it->cond_value && !pf) {
                    result += '\t' + name + "->";
                    result += tmp;
                    result += modifier;
                    result += '\n';
                }
                eit->SetIsDrawn();
            }
            if (cond.length() != 0) {
                if (lo) {
                    char tmp[32];
                    sprintf(tmp, "c_%llx", (uintptr_t)eit);
                    if (!it->block->IsEmptyBlock()) {
                        result += '\t';
                        result += tmp;
                        result += "->" + it->block->GetGraphVisDescription();
                        result += "[label=";
                        result += (!pf && it->cond_value) ? "T]" : "F]";
                        result += ";\n";
                    }
                    else {
                        std::string n = tmp;
                        std::string label;
                        label += "[label=";
                        label += (!pf && it->cond_value) ? "T]" : "F]";
                        result += it->block->GetEdgesForBlock(n, original, label);
                    }
                }
            }
            else {
                result += '\t' + name + " -> " + it->block->GetGraphVisDescription();
                result += modifier;
                result += ";\n";
            }
            
        }
        else {
            result += it->block->GetEdgesForBlock(name, original, "");
        }
    }
    return result;
}

std::string CBasicBlock::GetGraphVisDescription()
{
    if (visname.length() != 0)
        return visname;
    char tmp[16];
    sprintf(tmp, "%d", num);
    visname = tmp;
    return visname;
}

std::string CBasicBlock::GetGraphVisData()
{
    if (visunparse.length() != 0)
        return visunparse;
    std::string result;
    for (ControlFlowItem* it = start; it != NULL && (it->isLeader() == false || it == start); it = it->getNext()) {
        if (it->getStatement() != NULL) {
            int ln = it->GetLineNumber();
            char tmp[16];
            sprintf(tmp, "%d: ", ln);
            result += tmp;
            result += it->getStatement()->unparse();
        }
    }
    visunparse = result;
    return result;
}

int ControlFlowItem::GetLineNumber()
{
    if (getStatement() == NULL)
        return 0;
    if (getStatement()->lineNumber() == 0){
        if (getOriginalStatement() == NULL)
            return 0;
        return getOriginalStatement()->lineNumber();
    }
    return getStatement()->lineNumber();
}

bool CBasicBlock::IsEmptyBlock()
{
    for (ControlFlowItem* it = start; it != NULL && (it->isLeader() == false || it == start); it = it->getNext()) {        
        if (!it->IsEmptyCFI())
            return false;
    }
    return true;
}

AnalysedCallsList* CallData::GetDataForGraph(ControlFlowGraph* s)
{
    for (AnalysedCallsList* it = calls_list; it != NULL; it = it->next) {
        if (it->graph == s)
            return it;
    }
    return NULL;
}

ControlFlowGraph* GetControlFlowGraphWithCalls(bool main, SgStatement* start, CallData* calls, CommonData* commons)
{
    if (start == NULL) 
    {
        //is_correct = "no body for call found";
        return NULL;
    }

    ControlFlowGraph *cfgRet = NULL;
    /*
#if __SPF
    auto itF = CFG_cache.find(start);
    if (itF != CFG_cache.end())
    {
        calls = std::get<1>(itF->second);
        commons = std::get<2>(itF->second);
        return std::get<0>(itF->second);
    }
#endif*/
    doLoops l;
    ControlFlowItem *funcGraph = getControlFlowList(start, start->lastNodeOfStmt(), NULL, NULL, &l, calls, commons);
    fillLabelJumps(funcGraph);
    setLeaders(funcGraph);

    
    cfgRet = new ControlFlowGraph(false, main, funcGraph, NULL);
    //CFG_cache[start] = std::make_tuple(cfgRet, calls, commons);
    return cfgRet;
}

void FillCFGSets(ControlFlowGraph* graph)
{
    graph->privateAnalyzer();
}

static void ClearMemoryAfterDelay(ActualDelayedData* d)
{
    while (d != NULL) {
        CommonVarSet* cd = d->commons;
        while (cd != NULL) {
            CommonVarSet* t = cd;
            cd = cd->next;
            delete t;
        }
        delete d->buse;
        ActualDelayedData* tmp = d;
        d = d->next;
        delete tmp;
    }
}

static void FillPrivates(ControlFlowGraph* graph)
{
    ActualDelayedData* d = graph->ProcessDelayedPrivates(pCommons, mainProcedure, NULL, NULL, false, -1);
    ClearMemoryAfterDelay(d);
    if (privateDelayedList)
        privateDelayedList->PrintWarnings();
}

ActualDelayedData* CBasicBlock::GetDelayedDataForCall(CallAnalysisLog* log)
{
    for (ControlFlowItem* it = start; it != NULL && (!it->isLeader() || it == start); it = it->getNext())
    {
        AnalysedCallsList* c = it->getCall();
        void* cf = it->getFunctionCall();
        bool isFun = true;
        if (!cf) {
            cf = it->getStatement();
            isFun = false;
        }
        if (c != NULL && c != (AnalysedCallsList*)(-1) && c != (AnalysedCallsList*)(-2) && c->graph != NULL)
            return c->graph->ProcessDelayedPrivates(pCommons, c, log, cf, isFun, it->getProc()->file_id);
    }
    return NULL;
}

void PrivateDelayedItem::MoveFromPrivateToLastPrivate(CVarEntryInfo* var)
{
    VarItem* el = detected->belongs(var);
    if (el) {
        eVariableType storedType = el->var->GetVarType();
        detected->remove(el->var);
        lp->addToSet(var, NULL);
    }
}

void ActualDelayedData::RemoveVarFromCommonList(CommonVarSet* c)
{
    if (commons == NULL || c == NULL)
        return;
    if (c == commons) 
    {
        commons = commons->next;
        delete c;
        return;
    }
    CommonVarSet* prev = c;
    for (CommonVarSet* cur = c->next; cur != NULL; cur = cur->next) 
    {
        if (cur == c) 
        {
            prev->next = c->next;
            delete c;
            return;
        }
        else 
            prev = cur;        
    }
}

void ActualDelayedData::MoveVarFromPrivateToLastPrivate(CVarEntryInfo* var, CommonVarSet* c, VarSet* vs)
{
    original->MoveFromPrivateToLastPrivate(var);
    RemoveVarFromCommonList(c);
    if (vs) 
    {
        if (vs->belongs(var))
            vs->remove(var);
    }
}

int IsThisVariableAParameterOfSubroutine(AnalysedCallsList* lst, SgSymbol* s)
{
    if (!lst->header)
        return -1;
    int stored = SwitchFile(lst->file_id);
    SgProcHedrStmt* h = isSgProcHedrStmt(lst->header);
    if (!h)
        return -1;
    for (int i = 0; i < h->numberOfParameters(); i++) {
        SgSymbol* par = h->parameter(i);
        if (par == s) {
            SwitchFile(stored);
            return i;
        }
    }
    SwitchFile(stored);
    return -1;
}

ActualDelayedData* ControlFlowGraph::ProcessDelayedPrivates(CommonData* commons, AnalysedCallsList* call, CallAnalysisLog* log, void* c, bool isFun, int file_id)
{
    for (CallAnalysisLog* i = log; i != NULL; i = i->prev) {
        if (i->el == call) 
        {
            //TODO: add name of common
#if __SPF
            const wchar_t* rus = R158;
            Warning("Recursion is not analyzed for privates in common blocks '%s'", rus, "TODO!", PRIVATE_ANALYSIS_NO_RECURSION_ANALYSIS, call->header);
#else
            Warning("Recursion is not analyzed for privates in common blocks '%s'", "TODO!", PRIVATE_ANALYSIS_NO_RECURSION_ANALYSIS, call->header);
#endif
            return NULL;
        }
    }
    CallAnalysisLog* nl = new CallAnalysisLog();
    nl->el = call;
    nl->prev = log;
    if (log == NULL)
        nl->depth = 0;
    else
        nl->depth = log->depth + 1;
    log = nl;
    ActualDelayedData* my = NULL;
    for (CBasicBlock* bb = first; bb != NULL; bb = bb->getLexNext()) {
        if (bb->containsParloopStart()) {
            if (bb->GetDelayedData()) {
                ActualDelayedData* data = new ActualDelayedData();
                data->original = bb->GetDelayedData();
                data->commons = commons->GetCommonsForVarSet(data->original->getDetected(), call);
                VarSet* bu = new VarSet();
                bu->unite(data->original->getDelayed(), false);
                VarSet* tbu = new VarSet();
                while (!bu->isEmpty()) {
                    if (IS_BY_USE(bu->getFirst()->var->GetSymbol()))
                        tbu->addToSet(bu->getFirst()->var, NULL);
                    else {
                        CVarEntryInfo* old = bu->getFirst()->var;
                        int arg_id = IsThisVariableAParameterOfSubroutine(call, bu->getFirst()->var->GetSymbol());
                        if (arg_id != -1 && c != NULL) {
                            int stored = SwitchFile(file_id);
                            SgExpression* exp = GetProcedureArgument(isFun, c, arg_id);
                            if (isSgVarRefExp(exp) || isSgArrayRefExp(exp)) {
                                SgSymbol* sym = exp->symbol();
                                CVarEntryInfo* v;
                                if (isSgVarRefExp(exp)) {
                                    v = new CScalarVarEntryInfo(sym);
                                }
                                else {
                                    v = old->Clone(sym);
                                }
                                tbu->addToSet(v, NULL, old);
                            }
                            SwitchFile(stored);
                            
                        }
                    }
                    bu->remove(bu->getFirst()->var);
                }
                data->buse = tbu;
                delete bu;
                data->next = my;
                data->call = call;
                my = data;
            }
        }
        ActualDelayedData* calldata = bb->GetDelayedDataForCall(log);
        while (calldata != NULL) {
            CommonVarSet* nxt = NULL;
            for (CommonVarSet* t = calldata->commons; t != NULL; t = nxt) {
                nxt = t->next;
                CommonVarInfo* cvd = t->cvd;
                CommonDataItem* d = commons->IsThisCommonUsedInProcedure(cvd->parent, call);
                if (!d || commons->CanHaveNonScalarVars(d))
                    continue;
                CommonVarInfo* j = cvd->parent->info;
                CommonVarInfo* i = d->info;
                while (j != cvd) {
                    j = j->next;
                    if (i)
                        i = i->next;
                }
                if (!i)
                    continue;
                CVarEntryInfo* var = i->var;
                if (bb->getLexNext()->getLiveIn()->belongs(var->GetSymbol()) && calldata->original->getDelayed()->belongs(cvd->var)) {
                    calldata->MoveVarFromPrivateToLastPrivate(cvd->var, t, NULL);
                }
                if (bb->IsVarDefinedAfterThisBlock(var, false)) {
                    calldata->RemoveVarFromCommonList(t);
                }
                
            }
            if (log->el->header == calldata->call->header) {
                VarSet* pr = new VarSet();
                pr->unite(calldata->original->getDelayed(), false);
                pr->intersect(bb->getLexNext()->getLiveIn(), false, true);
                for (VarItem* exp = pr->getFirst(); exp != NULL; pr->getFirst()) {
                    calldata->MoveVarFromPrivateToLastPrivate(exp->var, NULL, NULL);
                    pr->remove(exp->var);
                }
                delete pr;
            }
            VarSet* tmp_use = new VarSet();
            tmp_use->unite(calldata->buse, false);
            while (!tmp_use->isEmpty()) {
                VarItem* v = tmp_use->getFirst();
                CVarEntryInfo* tmp = v->var->Clone(OriginalSymbol(v->var->GetSymbol()));
                if (bb->getLexNext()->getLiveIn()->belongs(tmp->GetSymbol(), true)) {
                    calldata->MoveVarFromPrivateToLastPrivate(v->ov ? v->ov : v->var, NULL, calldata->buse);
                }
                if (bb->IsVarDefinedAfterThisBlock(v->var, true)) {
                    calldata->buse->remove(v->ov ? v->ov : v->var);
                }
                delete tmp;
                tmp_use->remove(v->var);
            }
            delete tmp_use;
            ActualDelayedData* tmp = calldata->next;
            calldata->next = my;
            my = calldata;
            calldata = tmp;
        }
    }
    nl = log;
    log = log->prev;

    delete nl;
    return my;
}

extern graph_node* node_list;
void Private_Vars_Function_Analyzer(SgStatement* start);

void Private_Vars_Project_Analyzer()
{
    graph_node* node = node_list;
    while (node) {
        if (node->st_header) {
            int stored_file_id = SwitchFile(node->file_id);
            Private_Vars_Function_Analyzer(node->st_header);
            SwitchFile(stored_file_id);
        }
        node = node->next;
    }
}

// CALL function for PRIVATE analyzing
void Private_Vars_Function_Analyzer(SgStatement* start)
{
    //temporary state
#ifndef __SPF 
    if (!options.isOn(PRIVATE_ANALYSIS)){
        return;
    }
#endif

    if (start->variant() == PROG_HEDR) {
        Private_Vars_Analyzer(start);
    }
    /*
    ControlFlowItem* funcGraph = getControlFlowList(start, start->lastNodeOfStmt(), NULL, NULL, new doLoops());
    fillLabelJumps(funcGraph);
    setLeaders(funcGraph);
#if ACCAN_DEBUG
    printControlFlowList(funcGraph);
#endif
    ControlFlowItem* p = funcGraph;
    ControlFlowItem* pl_start = NULL;
    ControlFlowItem* pl_end = NULL;
    ControlFlowGraph* graph = new ControlFlowGraph(funcGraph, NULL);
    graph->privateAnalyzer();
    */
}
/*
// CALL function for PRIVATE analyzing
void Private_Vars_Analyzer(SgStatement *firstSt, SgStatement *lastSt)
{
    // temporary state
    //return;
    SgExpression* par_des = firstSt->expr(2);
    SgSymbol* l;
    SgForStmt* chk;
    int correct = 1;
    firstSt = firstSt->lexNext();
    while (correct && (par_des != NULL) && (par_des->lhs() != NULL) && ((l = par_des->lhs()->symbol()) != NULL)){
        if (firstSt->variant() == FOR_NODE){
            chk = isSgForStmt(firstSt);
            if (chk->symbol() != l)
                correct = 0;
            firstSt = firstSt->lexNext();
            par_des = par_des->rhs();
        }
        else{
            correct = 0;
        }
    }
    if (correct){
        doLoops* loops = new doLoops();
        ControlFlowItem* cfList = getControlFlowList(firstSt, lastSt, NULL, NULL, loops);
        fillLabelJumps(cfList);
        setLeaders(cfList);
#if ACCAN_DEBUG
        printControlFlowList(cfList);
#endif
        VarSet* priv = ControlFlowGraph(cfList, NULL).getPrivate();
#if ACCAN_DEBUG
        priv->print();
#endif
        clearList(cfList);
    }
}
*/

static void fillLabelJumps(ControlFlowItem* cfList)
{
    if (cfList != NULL){
        ControlFlowItem* temp = cfList;
        ControlFlowItem* temp2;
        unsigned int label_no = 0;
        while (temp != NULL){
            if (temp->getLabel() != NULL)
                label_no++;
            temp = temp->getNext();
        }
        LabelCFI* table = new LabelCFI[label_no + 1];
        unsigned int li = 0;
        for (temp = cfList; temp != NULL; temp = temp->getNext()){
            SgLabel* label;
            if ((label = temp->getLabel()) != NULL){
                table[li].item = temp;
                table[li++].l = label->id();
            }
            temp2 = temp;
        }
        temp = new ControlFlowItem(currentProcedure);
        temp2->AddNextItem(temp);
        table[label_no].item = temp2;
        table[label_no].l = -1;
        for (temp = cfList; temp != NULL; temp = temp->getNext()){
            SgLabel* jump = temp->getLabelJump();
            int l;
            if (jump != NULL){
                l = jump->id();
                for (unsigned int i = 0; i < label_no + 1; i++){
                    if (table[i].l == l || i == label_no){
                        temp->initJump(table[i].item);
                        break;
                    }
                }
            }
        }
        delete[] table;
    }
}

static void setLeaders(ControlFlowItem* cfList)
{
    if (cfList != NULL)
        cfList->setLeader();
    while (cfList != NULL)
    {
        if (cfList->getJump() != NULL)
        {
            cfList->getJump()->setLeader();
            if (cfList->getNext() != NULL)
                cfList->getNext()->setLeader();
        }
        if (cfList->getCall() != NULL)
        {
            if (cfList->getNext() != NULL)
                cfList->getNext()->setLeader();
        }
        cfList = cfList->getNext();
    }
}

static void clearList(ControlFlowItem *list)
{
    if (list != NULL)
    {
        if (list->getNext() != NULL)
            clearList(list->getNext());

        delete list;
    }
}

static ControlFlowItem* ifItem(SgStatement* stmt, ControlFlowItem* empty, SgStatement** lastAnStmt, doLoops* loops, bool ins, CallData* calls, CommonData* commons)
{
    if (stmt == NULL)
        return empty;
    SgIfStmt* cond;
    if (stmt->variant() == ELSEIF_NODE)
        cond = (SgIfStmt*)stmt;
    if (stmt->variant() == ELSEIF_NODE || (!ins && (cond = isSgIfStmt(stmt)) != NULL))
    {
        SgExpression* c = &(SgNotOp((cond->conditional()->copy())));
        ControlFlowItem *n, *j;
        ControlFlowItem* last;
        if ((n = getControlFlowList(cond->trueBody(), NULL, &last, lastAnStmt, loops, calls, commons)) == NULL)
            return NULL;
        j = ifItem(cond->falseBody(), empty, lastAnStmt, loops, cond->falseBody() != NULL ? cond->falseBody()->variant() == IF_NODE : false, calls, commons);
        ControlFlowItem* gotoEmpty = new ControlFlowItem(NULL, empty, j, NULL, currentProcedure);
        if (last != NULL)
            last->AddNextItem(gotoEmpty);
        else
            n = gotoEmpty;
        ControlFlowItem* tn = new ControlFlowItem(c, j, n, stmt->label(), currentProcedure);
        tn->setOriginalStatement(stmt);
        return tn;
    }
    else
    {
        ControlFlowItem* last;
        ControlFlowItem* ret;
        if ((ret = getControlFlowList(stmt, NULL, &last, lastAnStmt, loops, calls, commons)) == NULL)
            return NULL;
        last->AddNextItem(empty);
        return ret;
    }
}

static ControlFlowItem* switchItem(SgStatement* stmt, ControlFlowItem* empty, SgStatement** lastAnStmt, doLoops* loops, CallData* calls, CommonData* commons)
{
    SgSwitchStmt* sw = isSgSwitchStmt(stmt);
    SgExpression* sw_cond = (sw->selector());
    stmt = stmt->lexNext();
    *lastAnStmt = stmt;
    ControlFlowItem* last_sw = NULL;
    ControlFlowItem* first = NULL;
    bool is_def_last = false;
    SgStatement* not_def_last;
    while (stmt->variant() == CASE_NODE || stmt->variant() == DEFAULT_NODE)
    {
        if (stmt->variant() == DEFAULT_NODE){
            while (stmt->variant() != CONTROL_END && stmt->variant() != CASE_NODE)
                stmt = stmt->lexNext();
            if (stmt->variant() == CONTROL_END)
                stmt = stmt->lexNext();
            is_def_last = true;
            continue;
        }
        SgExpression* c = ((SgCaseOptionStmt*)stmt)->caseRange(0);
        SgExpression *lhs = NULL;
        SgExpression *rhs = NULL;
        if (c->variant() == DDOT){
            lhs = c->lhs();
            rhs = c->rhs();
            if (rhs == NULL)
                c = &(*lhs <= *sw_cond);
            else if (lhs == NULL)
                c = &(*sw_cond <= *rhs);
            else
                c = &(*lhs <= *sw_cond && *sw_cond <= *rhs);
        }
        else
            c = &SgNeqOp(*sw_cond, *c);
        ControlFlowItem *n, *j;
        ControlFlowItem* last;
        if ((n = getControlFlowList(stmt->lexNext(), NULL, &last, lastAnStmt, loops, calls, commons)) == NULL)
            return NULL;
        j = new ControlFlowItem(currentProcedure);
        ControlFlowItem* gotoEmpty = new ControlFlowItem(NULL, empty, j, NULL, currentProcedure);
        if (last != NULL)
            last->AddNextItem(gotoEmpty);
        else
            n = gotoEmpty;
        ControlFlowItem* cond = new ControlFlowItem(c, j, n, stmt->label(), currentProcedure);
        cond->setOriginalStatement(stmt);
        if (last_sw == NULL)
            first = cond;
        else
            last_sw->AddNextItem(cond);
        last_sw = j;
        is_def_last = false;
        not_def_last = *lastAnStmt;
        stmt = *lastAnStmt;
    }
    SgStatement* def = sw->defOption();
    if (def != NULL){
        ControlFlowItem* last;
        ControlFlowItem* n;
        if ((n = getControlFlowList(def->lexNext(), NULL, &last, lastAnStmt, loops, calls, commons)) == NULL)
            return NULL;
        if (last != NULL)
            last->AddNextItem(empty);
        if (last_sw == NULL)
            first = n;
        else
            last_sw->AddNextItem(n);
        last_sw = last;
    }
    last_sw->AddNextItem(empty);
    if (!is_def_last)
        *lastAnStmt = not_def_last;
    return first;
}

static ControlFlowItem* getControlFlowList(SgStatement *firstSt, SgStatement *lastSt, ControlFlowItem **last, SgStatement **lastAnStmt, doLoops* loops, CallData* calls, CommonData* commons)
{
    ControlFlowItem *list = new ControlFlowItem(currentProcedure);
    ControlFlowItem *cur = list;
    ControlFlowItem *pred = list;
    SgStatement *stmt;
    for (stmt = firstSt; (
        stmt != lastSt
        && stmt->variant() != CONTAINS_STMT
        && (lastSt != NULL || stmt->variant() != ELSEIF_NODE)
        && (lastSt != NULL || stmt->variant() != CASE_NODE)
        && (lastSt != NULL || stmt->variant() != DEFAULT_NODE));
        stmt = stmt->lexNext())
    {
        if (stmt->variant() == CONTROL_END)
        {
            if (isSgExecutableStatement(stmt))
                break;
        }

        cur = processOneStatement(&stmt, &pred, &list, cur, loops, calls, commons);
        if (cur == NULL)
        {
            clearList(list);
            return NULL;
        }
    }
    if (cur == NULL){
        cur = list = new ControlFlowItem(currentProcedure);
    }
    if (last != NULL)
        *last = cur;
    if (lastAnStmt != NULL)
        *lastAnStmt = stmt;
    return list;
}

AnalysedCallsList* CallData::IsHeaderInList(SgStatement* header)
{
    if (header == NULL)
        return NULL;
    AnalysedCallsList* p = calls_list;
    while (p != NULL) {
        if (p->header == header)
            return p;
        p = p->next;
    }
    return NULL;
}

void CallData::AssociateGraphWithHeader(SgStatement* st, ControlFlowGraph* gr)
{
    AnalysedCallsList* l = calls_list;
    while (l != NULL) {
        if (l->header == st) {
            if (gr == l->graph && gr != NULL)
                gr->AddRef();
            l->graph = gr;
            return;
        }
        l = l->next;
    }
    delete gr;
}

AnalysedCallsList* CallData::AddHeader(SgStatement* st, bool isFun, SgSymbol* name, int fid)
{
    //test
    bool add_intr = IsAnIntrinsicSubroutine(name->identifier()) != NULL;
    AnalysedCallsList* l = new AnalysedCallsList(st, (isIntrinsicFunctionNameACC(name->identifier()) || add_intr) && !IsUserFunctionACC(name), IsPureProcedureACC(name), isFun, name->identifier(), fid);
    l->next = calls_list;
    calls_list = l;
    return l;
}

extern int isStatementFunction(SgSymbol *s);

AnalysedCallsList* CallData::getLinkToCall(SgExpression* e, SgStatement* s, CommonData* commons)
{
    SgStatement* header = NULL;
    SgSymbol* name;
    bool isFun;
    graph_node* g = NULL;
    if (e == NULL) {
        //s - procedure call
        SgCallStmt* f = isSgCallStmt(s);
        SgSymbol* fdaf = f->name();
        if (ATTR_NODE(f->name()) != NULL)
            g = GRAPHNODE(f->name());
        if (g == NULL) {
            
            is_correct = "no header for procedure";
            failed_proc_name = f->name()->identifier();
            return (AnalysedCallsList*)(-1);
            
        }
        if (g)
            header = isSgProcHedrStmt(g->st_header);
        name = f->name();
        isFun = false;
        //intr = isIntrinsicFunctionNameACC(f->name()->identifier()) && !IsUserFunctionACC(f->name());
        //IsPureProcedureACC(f->name());
    }
    else {
        //e - function call
        SgFunctionCallExp* f = isSgFunctionCallExp(e);
        if (isStatementFunction(f->funName()))
            return (AnalysedCallsList*)(-2);
        if (ATTR_NODE(f->funName()) != NULL)
            g = GRAPHNODE(f->funName());
        if (g == NULL) {
            is_correct = "no header for function";
            failed_proc_name = f->funName()->identifier();
            return (AnalysedCallsList*)(-1);
        }
        header = isSgFuncHedrStmt(g->st_header);
        name = f->funName();
        isFun = true;
    }
    AnalysedCallsList* p;
    if ((p = IsHeaderInList(header))) {
        recursion_flag = recursion_flag || p->graph != NULL;
        return p;
    }
    AnalysedCallsList* prev = currentProcedure;
    currentProcedure = p = AddHeader(header, isFun, name, g->file_id);
    if (!p->isIntrinsic) {
        int stored = SwitchFile(g->file_id);
        
        ControlFlowGraph* graph = GetControlFlowGraphWithCalls(false, header, this, commons);
        //if (graph == NULL)
            //failed_proc_name = name->identifier();
        
        SwitchFile(stored);
        
        AssociateGraphWithHeader(header, graph);
        commons->MarkEndOfCommon(p);
    }
    currentProcedure = prev;
    return p;
}

static ControlFlowItem* GetFuncCallsForExpr(SgExpression* e, CallData* calls, ControlFlowItem** last, CommonData* commons, SgStatement* os)
{
    if (e == NULL) {
        *last = NULL;
        return NULL;
    }
    SgFunctionCallExp* f = isSgFunctionCallExp(e);
    if (f) {
        ControlFlowItem* head = new ControlFlowItem(NULL, NULL, currentProcedure, calls->getLinkToCall(e, NULL, commons));
        head->setOriginalStatement(os);
        ControlFlowItem* curl = head;
        head->setFunctionCall(f);
        ControlFlowItem* l1, *l2;
        ControlFlowItem* tail1 = GetFuncCallsForExpr(e->lhs(), calls, &l1, commons, os);
        ControlFlowItem* tail2 = GetFuncCallsForExpr(e->rhs(), calls, &l2, commons, os);
        *last = head;
        if (tail2 != NULL) {
            l2->AddNextItem(head);
            head = tail2;
        }
        if (tail1 != NULL) {
            l1->AddNextItem(head);
            head = tail1;
        }

        return head;
    }
    f = isSgFunctionCallExp(e->lhs());
    if (f) {
        ControlFlowItem* head = new ControlFlowItem(NULL, NULL, currentProcedure, calls->getLinkToCall(e->lhs(), NULL, commons));
        head->setOriginalStatement(os);
        head->setFunctionCall(f);
        ControlFlowItem* l1, *l2, *l3;
        ControlFlowItem* tail1 = GetFuncCallsForExpr(e->lhs()->lhs(), calls, &l1, commons, os);
        ControlFlowItem* tail2 = GetFuncCallsForExpr(e->lhs()->rhs(), calls, &l2, commons, os);
        ControlFlowItem* tail3 = GetFuncCallsForExpr(e->rhs(), calls, &l3, commons, os);
        *last = head;
        if (tail2 != NULL) {
            l2->AddNextItem(head);
            head = tail2;
        }
        if (tail1 != NULL) {
            l1->AddNextItem(head);
            head = tail1;
        }
        if (tail3 != NULL) {
            (*last)->AddNextItem(tail3);
            *last = l3;
        }
        return head;
    }
    return GetFuncCallsForExpr(e->rhs(), calls, last, commons, os);
}

static ControlFlowItem* AddFunctionCalls(SgStatement* st, CallData* calls, ControlFlowItem** last, CommonData* commons)
{
    ControlFlowItem* retv = GetFuncCallsForExpr(st->expr(0), calls, last, commons, st);
    ControlFlowItem* l2 = NULL;
    ControlFlowItem* second = GetFuncCallsForExpr(st->expr(1), calls, &l2, commons, st);
    if (retv == NULL) {
        retv = second;
        *last = l2;
    }
    else if (second != NULL) {
        (*last)->AddNextItem(second);
        *last = l2;
    }
    ControlFlowItem* l3 = NULL;
    ControlFlowItem* third = GetFuncCallsForExpr(st->expr(2), calls, &l3, commons, st);
    if (retv == NULL) {
        retv = third;
        *last = l3;
    }
    else if (third != NULL) {
        (*last)->AddNextItem(third);
        *last = l3;
    }
    return retv;
}

void DoLoopDataList::AddLoop(int file_id, SgStatement* st, SgExpression* l, SgExpression* r, SgExpression* step, SgSymbol* lv)
{
    DoLoopDataItem* nt = new DoLoopDataItem();
    nt->file_id = file_id;
    nt->statement = st;
    nt->l = l;
    nt->r = r;
    nt->st = step;
    nt->loop_var = lv;
    nt->next = list;
    list = nt;
}

DoLoopDataList::~DoLoopDataList()
{
#if __SPF
    removeFromCollection(this);
    return;
#endif
    while (list != NULL) {
        DoLoopDataItem* t = list->next;
        delete list;
        list = t;
    }
}

static ControlFlowItem* processOneStatement(SgStatement** stmt, ControlFlowItem** pred, ControlFlowItem **list, ControlFlowItem* oldcur, doLoops* loops, CallData* calls, CommonData* commons)
{
    ControlFlowItem* lastf;
    ControlFlowItem* funcs = AddFunctionCalls(*stmt, calls, &lastf, commons);
    if (funcs != NULL) {
        if (*pred != NULL)
            (*pred)->AddNextItem(funcs);
        else
            *list = funcs;
        *pred = lastf;
    }

    switch ((*stmt)->variant())
    {
        case IF_NODE:
        {
            ControlFlowItem* emptyAfterIf = new ControlFlowItem(currentProcedure); //empty item to avoid second pass
            /*
            if ((*stmt)->hasLabel()){
                ControlFlowItem* emptyBeforeIf = new ControlFlowItem();
                emptyBeforeIf->setLabel((*stmt)->label());
                if (*pred != NULL)
                    (*pred)->AddNextItem(emptyBeforeIf);
                else
                    *list = emptyBeforeIf;
                *pred = emptyBeforeIf;
            }
            */
            ControlFlowItem* cur = ifItem(*stmt, emptyAfterIf, stmt, loops, false, calls, commons);
            emptyAfterIf->setLabel((*stmt)->label());
            if (*pred != NULL)
                (*pred)->AddNextItem(cur);
            else
                *list = cur;
            return (*pred = emptyAfterIf);
        }
        case ASSIGN_STAT:
        case POINTER_ASSIGN_STAT:
        case PROC_STAT:
        case PRINT_STAT:
        case READ_STAT:
        case WRITE_STAT:
        case ALLOCATE_STMT:
        case DEALLOCATE_STMT:
        {
            ControlFlowItem* cur = new ControlFlowItem(*stmt, NULL, currentProcedure, (*stmt)->variant() == PROC_STAT ? calls->getLinkToCall(NULL, *stmt, commons) : NULL);
            if (*pred != NULL)
                (*pred)->AddNextItem(cur);
            else
                *list = cur;
            return (*pred = loops->checkStatementForLoopEnding(cur->getLabel() ? cur->getLabel()->id() : -1, cur));
        }
        case LOGIF_NODE:
        {
            ControlFlowItem* emptyAfterIf = new ControlFlowItem(currentProcedure); //empty item to avoid second pass
            SgLogIfStmt* cond = isSgLogIfStmt(*stmt);
            SgLabel* lbl = (*stmt)->label();
            SgExpression* c = &(SgNotOp((cond->conditional()->copy())));
            ControlFlowItem* cur = new ControlFlowItem(c, emptyAfterIf, NULL, (*stmt)->label(), currentProcedure);
            cur->setOriginalStatement(*stmt);
            if (*pred != NULL)
                (*pred)->AddNextItem(cur);
            else
                *list = cur;
            *stmt = (*stmt)->lexNext();
            ControlFlowItem* body;
            if ((body = processOneStatement(stmt, &cur, list, cur, loops, calls, commons)) == NULL){
                return NULL;
            }
            body->AddNextItem(emptyAfterIf);
            return (*pred = loops->checkStatementForLoopEnding(lbl ? lbl->id() : -1, emptyAfterIf));
        }
        case WHILE_NODE:
        {
            SgWhileStmt* cond = isSgWhileStmt(*stmt);
            bool isEndDo = (*stmt)->lastNodeOfStmt()->variant() == CONTROL_END;
            SgExpression* c;
            if (cond->conditional())
                c = &(SgNotOp((cond->conditional()->copy())));
            else
                c = new SgValueExp(1);
            ControlFlowItem* emptyAfterWhile = new ControlFlowItem(currentProcedure);
            ControlFlowItem* emptyBeforeBody = new ControlFlowItem(currentProcedure);
            ControlFlowItem* cur = new ControlFlowItem(c, emptyAfterWhile, emptyBeforeBody, (*stmt)->label(), currentProcedure);
            cur->setOriginalStatement(cond);
            ControlFlowItem* gotoStart = new ControlFlowItem(NULL, cur, emptyAfterWhile, NULL, currentProcedure);
            ControlFlowItem* emptyBefore = new ControlFlowItem(NULL, (ControlFlowItem*)NULL, cur, cond->label(), currentProcedure);
            SgVarRefExp* doName = (isSgVarRefExp((*stmt)->expr(2)));
            int lbl = -1;
            if (!isEndDo){
                SgStatement* end = lastStmtOfDoACC(cond);
                if (end->controlParent() && end->controlParent()->variant() == LOGIF_NODE)
                    lbl = end->controlParent()->label()->id();
                else
                    lbl = end->label()->id();
            }
            loops->addLoop(lbl, doName ? doName->symbol() : NULL, gotoStart, emptyAfterWhile);
            ControlFlowItem* n, *last;
            if (isEndDo){
                if ((n = getControlFlowList((*stmt)->lexNext(), NULL, &last, stmt, loops, calls, commons)) == NULL)
                    return NULL;
                emptyBeforeBody->AddNextItem(n);
                loops->endLoop(last);
            }
            if (*pred != NULL)
                (*pred)->AddNextItem(emptyBefore);
            else
                *list = emptyBefore;
            if (isEndDo)
                return (*pred = emptyAfterWhile);
            return (*pred = emptyBeforeBody);
        }
        case FOR_NODE:
        {
            SgForStmt* fst = isSgForStmt(*stmt);
#if __SPF
            SgStatement *p = NULL;
            for (int i = 0; i < fst->numberOfAttributes(); ++i)
            {
                if (fst->attributeType(i) == SPF_ANALYSIS_DIR)
                {
                    p = (SgStatement *)(fst->getAttribute(i)->getAttributeData());
                    break;
                }
            }
            bool isParLoop = (p && p->variant() == SPF_ANALYSIS_DIR);
#else
            SgStatement* p = (*stmt)->lexPrev();
            bool isParLoop = (p && p->variant() == DVM_PARALLEL_ON_DIR);
#endif
            SgExpression* pl = NULL;
            SgExpression* pPl = NULL;
            bool pl_flag = true;
            if (isParLoop){
#if __SPF
                SgExpression* el = p->expr(0);
#else
                SgExpression* el = p->expr(1);
#endif
                pPl = el;
                while (el != NULL) {
                    SgExpression* e = el->lhs();
                    if (e->variant() == ACC_PRIVATE_OP) {
                        pl = e;
                        break;
                    }
                    pPl = el;
                    pl_flag = false;
                    el = el->rhs();
                }
                //pl->unparsestdout();
            }
            bool isEndDo = fst->isEnddoLoop();
            SgExpression* lh = new SgVarRefExp(fst->symbol());
            SgStatement* fa = new SgAssignStmt(*lh, *fst->start());
            bool needs_goto = true;
#if !__SPF
            // create goto edge if can not calculate count of loop's iterations
            if (fst->start()->variant() == INT_VAL && fst->end()->variant() == INT_VAL && fst->start()->valueInteger() < fst->end()->valueInteger())
                needs_goto = false;
#endif
            //fa->setLabel(*(*stmt)->label());
            ControlFlowItem* last;
            ControlFlowItem* emptyAfterDo = new ControlFlowItem(currentProcedure);
            ControlFlowItem* emptyBeforeDo = new ControlFlowItem(currentProcedure);
            ControlFlowItem* gotoEndInitial = NULL;
            if (needs_goto) {
                SgExpression* sendc = new SgExpression(GT_OP, new SgVarRefExp(fst->symbol()), fst->end(), NULL);
                gotoEndInitial = new ControlFlowItem(sendc, emptyAfterDo, emptyBeforeDo, NULL, currentProcedure, true);
                gotoEndInitial->setOriginalStatement(fst);
            }
            ControlFlowItem* stcf = new ControlFlowItem(fa, needs_goto ? gotoEndInitial : emptyBeforeDo, currentProcedure);
            stcf->setOriginalStatement(fst);
            stcf->setLabel((*stmt)->label());
            SgExpression* rh = new SgExpression(ADD_OP, new SgVarRefExp(fst->symbol()), new SgValueExp(1), NULL);
            SgStatement* add = new SgAssignStmt(*lh, *rh);
            SgExpression* endc = new SgExpression(GT_OP, new SgVarRefExp(fst->symbol()), fst->end(), NULL);
            ControlFlowItem* gotoStart = new ControlFlowItem(NULL, emptyBeforeDo, emptyAfterDo, NULL, currentProcedure);
            ControlFlowItem* gotoEnd = new ControlFlowItem(endc, emptyAfterDo, gotoStart, NULL, currentProcedure);
            gotoEnd->setOriginalStatement(fst);
            if (needs_goto) {
                gotoEnd->SetConditionFriend(gotoEndInitial);
            }
            ControlFlowItem* loop_d = new ControlFlowItem(add, gotoEnd, currentProcedure);
            loop_d->setOriginalStatement(fst);
            ControlFlowItem* loop_emp = new ControlFlowItem(NULL, loop_d, currentProcedure);
            SgVarRefExp* doName = (isSgVarRefExp((*stmt)->expr(2)));
            int lbl = -1;
            if (!isEndDo){
                SgStatement* end = lastStmtOfDoACC(fst);
                if (end->variant() == LOGIF_NODE)
                    lbl = end->controlParent()->label()->id();
                else
                    lbl = end->label()->id();
            }
            loops->addLoop(lbl, doName ? doName->symbol() : NULL, loop_emp, emptyAfterDo);
            doLoopList->AddLoop(current_file_id, *stmt, fst->start(), fst->end(), fst->step(), fst->symbol());
            if (isParLoop) {
#if __SPF
                // all loop has depth == 1 ? is it correct?
                int k = 1;
#else
                SgExpression* par_des = p->expr(2);
                int k = 0;
                while (par_des != NULL && par_des->lhs() != NULL) {
                    k++;
                    par_des = par_des->rhs();
                }
#endif
                loops->setParallelDepth(k, pl, p, pPl, pl_flag);
            }

            if (loops->isLastParallel()) {
                SgExpression* ex = loops->getPrivateList();
                emptyBeforeDo->MakeParloopStart();
                bool f;
                SgExpression* e = loops->getExpressionToModifyPrivateList(&f);
                emptyBeforeDo->setPrivateList(ex, loops->GetParallelStatement(), e, f);
                loop_d->MakeParloopEnd();
            }
            if (isEndDo){
                ControlFlowItem* body;
                if ((body = getControlFlowList(fst->body(), NULL, &last, stmt, loops, calls, commons)) == NULL)
                    return NULL;
                emptyBeforeDo->AddNextItem(body);
                loops->endLoop(last);
            }
            if (*pred != NULL)
                (*pred)->AddNextItem(stcf);
            else
                *list = stcf;
            if (isEndDo)
                return (*pred = emptyAfterDo);
            return (*pred = emptyBeforeDo);
        }
        case GOTO_NODE:
        {
            SgGotoStmt* gst = isSgGotoStmt(*stmt);
            ControlFlowItem* gt = new ControlFlowItem(NULL, gst->branchLabel(), NULL, gst->label(), currentProcedure);
            if (*pred != NULL)
                (*pred)->AddNextItem(gt);
            else
                *list = gt;
            return (*pred = gt);
        }
        case ARITHIF_NODE:
        {
            SgArithIfStmt* arif = (SgArithIfStmt*)(*stmt);
            ControlFlowItem* gt3 = new ControlFlowItem(NULL, ((SgLabelRefExp*)(*stmt)->expr(1)->rhs()->rhs()->lhs())->label(), NULL, NULL, currentProcedure);
            ControlFlowItem* gt2 = new ControlFlowItem(&SgEqOp(*(arif->conditional()), *new SgValueExp(0)), ((SgLabelRefExp*)(*stmt)->expr(1)->rhs()->lhs())->label(), gt3, NULL, currentProcedure);
            gt2->setOriginalStatement(arif);
            ControlFlowItem* gt1 = new ControlFlowItem(&(*arif->conditional() < *new SgValueExp(0)), ((SgLabelRefExp*)(*stmt)->expr(1)->lhs())->label(), gt2, (*stmt)->label(), currentProcedure);
            gt1->setOriginalStatement(arif);
            if (*pred != NULL)
                (*pred)->AddNextItem(gt1);
            else
                *list = gt1;
            return (*pred = gt3);
        }
        case COMGOTO_NODE:
        {
            SgComputedGotoStmt* cgt = (SgComputedGotoStmt*)(*stmt);
            SgExpression* label = cgt->labelList();
            int i = 0;
            SgLabel* lbl = ((SgLabelRefExp *)(label->lhs()))->label();
            ControlFlowItem* gt = new ControlFlowItem(&SgEqOp(*(cgt->exp()), *new SgValueExp(++i)), lbl, NULL, cgt->label(), currentProcedure);
            gt->setOriginalStatement(cgt);
            if (*pred != NULL)
                (*pred)->AddNextItem(gt);
            else
                *list = gt;
            ControlFlowItem* old = gt;
            while ((label = label->rhs()))
            {
                lbl = ((SgLabelRefExp *)(label->lhs()))->label();
                gt = new ControlFlowItem(&SgEqOp(*(cgt->exp()), *new SgValueExp(++i)), lbl, NULL, NULL, currentProcedure);
                gt->setOriginalStatement(cgt);
                old->AddNextItem(gt);
                old = gt;
            }
            return (*pred = gt);
        }
        case SWITCH_NODE:
        {
             ControlFlowItem* emptyAfterSwitch = new ControlFlowItem(currentProcedure);
             ControlFlowItem* cur = switchItem(*stmt, emptyAfterSwitch, stmt, loops, calls, commons);
             emptyAfterSwitch->setLabel((*stmt)->label());
             if (*pred != NULL)
                 (*pred)->AddNextItem(cur);
             else
                 *list = cur;
             return (*pred = emptyAfterSwitch);
        }
        case CONT_STAT:
        {
             ControlFlowItem* cur = new ControlFlowItem(NULL, (ControlFlowItem*)NULL, NULL, (*stmt)->label(), currentProcedure);
             if (*pred != NULL)
                 (*pred)->AddNextItem(cur);
             else
                 *list = cur;
             return (*pred = loops->checkStatementForLoopEnding(cur->getLabel() ? cur->getLabel()->id() : -1, cur));
        }
        case CYCLE_STMT:
        {
             SgSymbol* ref = (*stmt)->symbol();
             ControlFlowItem* cur = new ControlFlowItem(NULL, loops->getSourceForCycle(ref), NULL, (*stmt)->label(), currentProcedure);
             if (*pred != NULL)
                 (*pred)->AddNextItem(cur);
             else
                 *list = cur;
             return (*pred = cur);
        }
        case EXIT_STMT:
        {
             SgSymbol* ref = (*stmt)->symbol();
             ControlFlowItem* cur = new ControlFlowItem(NULL, loops->getSourceForExit(ref), NULL, (*stmt)->label(), currentProcedure);
             if (*pred != NULL)
                 (*pred)->AddNextItem(cur);
             else
                 *list = cur;
             return (*pred = cur);
        }
        case COMMENT_STAT:
            return *pred;
        case COMM_STAT:
        {
            commons->RegisterCommonBlock(*stmt, currentProcedure);
            return *pred;
        }
        default:
            return *pred;
            //return NULL;
    }
}

ControlFlowGraph::ControlFlowGraph(bool t, bool m, ControlFlowItem* list, ControlFlowItem* end) : temp(t), main(m), refs(1), def(NULL), use(NULL), pri(NULL), common_def(NULL), common_use(NULL), hasBeenAnalyzed(false)
#ifdef __SPF
, pointers(set<SymbolKey>())
#endif
{
#if __SPF
    addToCollection(__LINE__, __FILE__, this, 30);
#endif
    int n = 0;
    ControlFlowItem* orig = list;
    CBasicBlock* prev = NULL;
    CBasicBlock* start = NULL;
    int stmtNo = 0;
    bool ns = list->isEnumerated();
    if (list != NULL && !ns){
        while (list != NULL && list != end)
        {
            list->setStmtNo(++stmtNo);
            list = list->getNext();
        }
    }
    ControlFlowItem* last_prev = NULL;
    list = orig;
    while (list != NULL && list != end)
    {
        CBasicBlock* bb = new CBasicBlock(t, list, ++n, this, list->getProc());
        last = bb;
        bb->setPrev(prev);
        if (prev != NULL){
            prev->setNext(bb);
            if (!last_prev->isUnconditionalJump()){
                bb->addToPrev(prev, last_prev->IsForJumpFlagSet(), false, last_prev);
                prev->addToSucc(bb, last_prev->IsForJumpFlagSet(), false, last_prev);
            }
        }
        if (start == NULL)
            start = bb;
        prev = bb;
        while (list->getNext() != NULL && list->getNext() != end && !list->getNext()->isLeader()){
            list->setBBno(n);
            list = list->getNext();
        }
        list->setBBno(n);
        last_prev = list;
        list = list->getNext();
    }
    list = orig;
    while (list != NULL && list != end)
    {
        ControlFlowItem* target;
        if ((target = list->getJump()) != NULL)
        {
//            //no back edges
//            if (target->getBBno() > list->getBBno())
//            { 
                CBasicBlock* tmp1 = start;
                CBasicBlock* tmp2 = start;
                for (int i = 1; i < target->getBBno() || i < list->getBBno(); i++)
                {
                    if (i < list->getBBno()) {
                        tmp2 = tmp2->getLexNext();
                        if (!tmp2)
                            break;
                    }
                    if (i < target->getBBno()) {
                        tmp1 = tmp1->getLexNext();
                        if (!tmp1)
                            break;
                    }
                }
                if (tmp1 && tmp2) {
                    tmp1->addToPrev(tmp2, list->IsForJumpFlagSet(), true, list);
                    tmp2->addToSucc(tmp1, list->IsForJumpFlagSet(), true, list);
                }
//            }
        }
        list = list->getNext();
    }
    start->markAsReached();
    first = start;
    common_use = NULL;
    cuf = false;
    common_def = NULL;
    cdf = false;
}

CommonDataItem* CommonData::IsThisCommonVar(VarItem* item, AnalysedCallsList* call)
{
    for (CommonDataItem* it = list; it != NULL; it = it->next) {
        if (it->proc == call) {
            for (CommonVarInfo* inf = it->info; inf != NULL; inf = inf->next) {
                if (inf->var && item->var && *inf->var == *item->var)
                    return it;
            }
        }
    }
    return NULL;
}

CommonDataItem* CommonData::GetItemForName(const string &name, AnalysedCallsList *call)
{
    for (CommonDataItem* it = list; it != NULL; it = it->next) {
        if (it->name == name && it->proc == call)
            return it;
    }
    return NULL;
}

void CommonData::RegisterCommonBlock(SgStatement *st, AnalysedCallsList *cur)
{
    //TODO: multiple common blocks in one procedure with same name
    for (SgExpression *common = st->expr(0); common; common = common->rhs())
    {
        bool newBlock = false;
        SgExprListExp* vars = (SgExprListExp*)common->lhs();
        if (vars == NULL)
            continue;

        const string currCommonName = (common->symbol()) ? common->symbol()->identifier() : "spf_unnamed";

        CommonDataItem* it = GetItemForName(currCommonName, cur);
        if (!it) {
            it = new CommonDataItem();
            it->cb = st;
            it->name = currCommonName;
            it->isUsable = true;
            it->proc = cur;
            it->first = cur;
            it->onlyScalars = true;
            newBlock = true;

            for (CommonDataItem *i = list; i != NULL; i = i->next)
                if (i->name == currCommonName && i->isUsable)
                    it->first = i->first;
        }
        it->commonRefs.push_back(common);

        for (int i = 0; i < vars->length(); ++i)
        {
            SgVarRefExp *e = isSgVarRefExp(vars->elem(i));
            if (e && !IS_ARRAY(e->symbol()))
            {
                CommonVarInfo* c = new CommonVarInfo();
                c->var = new CScalarVarEntryInfo(e->symbol());
                c->isPendingLastPrivate = false;
                c->isInUse = false;
                c->parent = it;
                c->next = it->info;
                it->info = c;
            }
            else if (isSgArrayRefExp(vars->elem(i))) {
                it->onlyScalars = false;
            }
            else {
                CommonVarInfo* c = new CommonVarInfo();
                c->var = new CArrayVarEntryInfo(vars->elem(i)->symbol(), isSgArrayRefExp(vars->elem(i)));
                c->isPendingLastPrivate = false;
                c->isInUse = false;
                c->parent = it;
                c->next = it->info;
                it->info = c;
                it->onlyScalars = false;
            }
        }

        if (newBlock)
        {
            it->next = list;
            list = it;
        }
    }
}

void CommonData::MarkEndOfCommon(AnalysedCallsList* cur)
{
    for (CommonDataItem* i = list; i != NULL; i = i->next)
    {
        if (i->first == cur)
            i->isUsable = false;
    }
}

void CBasicBlock::markAsReached()
{
    prev_status = 1;
    BasicBlockItem* s = succ;
    while (s != NULL){
        CBasicBlock* b = s->block;
        if (b->prev_status == -1)
            b->markAsReached();
        s = s->next;
    }
}

bool ControlFlowGraph::ProcessOneParallelLoop(ControlFlowItem* lstart, CBasicBlock* of, CBasicBlock*& p, bool first)
{
    int stored_fid = SwitchFile(lstart->getProc()->file_id);
    ControlFlowItem* lend;
    if (is_correct != NULL)
    {
        const char* expanded_log;
        char* tmp = NULL;
        if (failed_proc_name)
        {
            tmp = new char[strlen(is_correct) + 2 + strlen(failed_proc_name) + 1];
            strcpy(tmp, is_correct);
            strcat(tmp, ": ");
            strcat(tmp, failed_proc_name);
            expanded_log = tmp;
        }
        else
            expanded_log = is_correct;
#if __SPF
        const wchar_t* rus = R159;
        Warning("Private analysis is not conducted for loop: '%s'", rus, expanded_log ? expanded_log : "", PRIVATE_ANALYSIS_NOT_CONDUCTED, lstart->getPrivateListStatement());
#else
        Warning("Private analysis is not conducted for loop: '%s'", expanded_log ? expanded_log : "", PRIVATE_ANALYSIS_NOT_CONDUCTED, lstart->getPrivateListStatement());
#endif
        if (tmp)
            delete[] tmp;

    }
    else
    {
        while ((lend = p->containsParloopEnd()) == NULL)
        {
            p->PrivateAnalysisForAllCalls();
            p = p->getLexNext();
            ControlFlowItem* mstart;
            if ((mstart = p->containsParloopStart()) != NULL)
            {
                CBasicBlock* mp = p;
                if (first) {
                    if (!ProcessOneParallelLoop(mstart, of, mp, false)) {
                        SwitchFile(stored_fid);
                        return false;
                    }
                }
            }
        }
        CBasicBlock* afterParLoop = p->getLexNext()->getLexNext();
        VarSet* l_pri = ControlFlowGraph(true, false, lstart, lend).getPrivate();
        if (is_correct != NULL)
        {
            const char* expanded_log;
            char* tmp = NULL;
            if (failed_proc_name)
            {
                tmp = new char[strlen(is_correct) + 2 + strlen(failed_proc_name) + 1];
                strcpy(tmp, is_correct);
                strcat(tmp, ": ");
                strcat(tmp, failed_proc_name);
                expanded_log = tmp;
            }
            else
                expanded_log = is_correct;

#if __SPF
            const wchar_t* rus = R159;
            Warning("Private analysis is not conducted for loop: '%s'", rus, expanded_log ? expanded_log : "", PRIVATE_ANALYSIS_NOT_CONDUCTED, lstart->getPrivateListStatement());
#else
            Warning("Private analysis is not conducted for loop: '%s'", expanded_log ? expanded_log : "", PRIVATE_ANALYSIS_NOT_CONDUCTED, lstart->getPrivateListStatement());
#endif
            if (tmp)
                delete[] tmp;
            SwitchFile(stored_fid);
            return false;
        }
        VarSet* p_pri = new VarSet();
        SgExpression* ex_p = lstart->getPrivateList();
        if (ex_p != NULL)
            ex_p = ex_p->lhs();
        for (; ex_p != NULL; ex_p = ex_p->rhs())
        {
            SgVarRefExp* pr;
            if (pr = isSgVarRefExp(ex_p->lhs()))
            {
                CScalarVarEntryInfo* tmp = new CScalarVarEntryInfo(pr->symbol());
                p_pri->addToSet(tmp, NULL);
                delete tmp;
            }
            SgArrayRefExp* ar;
            if (ar = isSgArrayRefExp(ex_p->lhs()))
            {
                CArrayVarEntryInfo* tmp = new CArrayVarEntryInfo(ar->symbol(), ar);
                p_pri->addToSet(tmp, NULL);
                delete tmp;
            }
        }

        VarSet* live = afterParLoop->getLiveIn();
        VarSet* adef = afterParLoop->getDef();
        VarSet* pri = new VarSet();
        VarSet* tmp = new VarSet();
        VarSet* delay = new VarSet();
        tmp->unite(l_pri, false);

        for (VarItem* exp = tmp->getFirst(); exp != NULL; exp = tmp->getFirst())
        {
            if (!afterParLoop->IsVarDefinedAfterThisBlock(exp->var, false))
                delay->addToSet(exp->var, NULL);
            tmp->remove(exp->var);
        }
        delete tmp;
        pri->unite(l_pri, false);
        pri->minus(live, true);
        privateDelayedList = new PrivateDelayedItem(pri, p_pri, l_pri, lstart, privateDelayedList, this, delay, current_file_id);
        of->SetDelayedData(privateDelayedList);
    }
    SwitchFile(stored_fid);
    return true;
}

void ControlFlowGraph::privateAnalyzer()
{
    if (hasBeenAnalyzed)
        return;
    CBasicBlock* p = first;
    /*
    printf("GRAPH:\n");
    while (p != NULL){
        printf("block %d: ", p->getNum());
        if (p->containsParloopStart())
            printf("start");
        if (p->containsParloopEnd())
            printf("end");
        p->print();
        p = p->getLexNext();
    }
    */
    p = first;
    liveAnalysis();
    while (1) 
    {
        ControlFlowItem* lstart;
        CBasicBlock* of = p;
        p->PrivateAnalysisForAllCalls();
        if ((lstart = p->containsParloopStart()) != NULL) 
        {
            if (!ProcessOneParallelLoop(lstart, of, p, true))
                break;
        }
        if (p == last)
            break;
        p = p->getLexNext();
    }
    hasBeenAnalyzed = true;
}

/*#ifdef __SPF
void PrivateDelayedItem::PrintWarnings()
{
    if (next)
        next->PrintWarnings();
    lp->minus(detected);
    while (!detected->isEmpty()) {
        SgVarRefExp* var = detected->getFirst();
        detected->remove(var);
        Warning("Variable '%s' detected as private", var->unparse(), PRIVATE_ANALYSIS_ADD_VAR, lstart->getPrivateListStatement());
    }
    while (!lp->isEmpty()) {
        SgVarRefExp* var = lp->getFirst();
        lp->remove(var);
        Warning("Variable '%s' detected as last private", var->unparse(), PRIVATE_ANALYSIS_ADD_VAR, lstart->getPrivateListStatement());
    }
    if (detected)
        delete detected;
    if (original)
        delete original;
    if (lp)
        delete lp;
}
#else*/

bool CArrayVarEntryInfo::HasActiveElements() const
{
    bool result = false;
    if (disabled)
        return false;
    if (subscripts == 0)
        return true;
    for (int i = 0; i < subscripts; i++) 
    {
        if (!data[i].defined)
            return false;
        if (data[i].left_bound != data[i].right_bound)
            result = true;
        if (data[i].left_bound == data[i].right_bound && data[i].bound_modifiers[0] <= data[i].bound_modifiers[1])
            result = true;
    }
    return result;
}

void CArrayVarEntryInfo::MakeInactive()
{
    disabled = true;
    for (int i = 0; i < subscripts; i++) 
    {
        data[i].left_bound = data[i].right_bound = NULL;
        data[i].bound_modifiers[0] = data[i].bound_modifiers[1] = 0;
    }
}

void PrivateDelayedItem::PrintWarnings()
{
    if (next)
        next->PrintWarnings();
    int stored_fid = SwitchFile(file_id);
    total_privates += detected->count();
    total_pl++;
    lp->minus(detected);
    detected->LeaveOnlyRecords();
    detected->RemoveDoubtfulCommonVars(lstart->getProc());
    VarSet* test1 = new VarSet();
    test1->unite(detected, false);
    VarSet* test2 = new VarSet();
    test2->unite(original, false);
    test2->minus(detected);
    test1->minus(original);
    int extra = 0, missing = 0;
    SgExpression* prl = lstart->getPrivateList();
    SgStatement* prs = lstart->getPrivateListStatement();
    if (prl == NULL && !test1->isEmpty()) 
    {
        SgExpression* lst = new SgExprListExp();
        prl = new SgExpression(ACC_PRIVATE_OP);
        lst->setLhs(prl);
        lst->setRhs(NULL);
#if __SPF
        SgExpression* clauses = prs->expr(0);
#else
        SgExpression* clauses = prs->expr(1);
#endif
        if (clauses) {
            while (clauses->rhs() != NULL)
                clauses = clauses->rhs();
            clauses->setRhs(lst);
        }
        else {
#if __SPF
            prs->setExpression(0, *lst);
#else
            prs->setExpression(1, *lst);
#endif
        }
    }
    SgExpression* op = prl;

    while (!test2->isEmpty()) {
        //printf("EXTRA IN PRIVATE LIST: ");
        //test2->print();
        extra = 1;
        VarItem* var = test2->getFirst();
        CVarEntryInfo* syb = var->var->Clone();
        int change_fid = var->file_id;
        test2->remove(var->var);
        int stored_fid = SwitchFile(change_fid);
        if (syb->GetVarType() != VAR_REF_ARRAY_EXP)
        {
#if __SPF
            const wchar_t* rus = R160;
            Warning("var '%s' from private list wasn't classified as private", rus, syb->GetSymbol()->identifier(), PRIVATE_ANALYSIS_REMOVE_VAR, lstart->getPrivateListStatement());
#else
            Warning("var '%s' from private list wasn't classified as private", syb->GetSymbol()->identifier(), PRIVATE_ANALYSIS_REMOVE_VAR, lstart->getPrivateListStatement());
#endif
        }
        else 
        {
            CArrayVarEntryInfo* tt = (CArrayVarEntryInfo*)syb;
            if (tt->HasActiveElements())
            {
#if __SPF
                const wchar_t* rus = R161;
                Warning("array '%s' from private list wasn't classified as private", rus, syb->GetSymbol()->identifier(), PRIVATE_ANALYSIS_REMOVE_VAR, lstart->getPrivateListStatement());
#else
                Warning("array '%s' from private list wasn't classified as private", syb->GetSymbol()->identifier(), PRIVATE_ANALYSIS_REMOVE_VAR, lstart->getPrivateListStatement());
#endif
            }
        }
        delete(syb);
        SwitchFile(stored_fid);
    }
    while (!test1->isEmpty()) {
        //printf("MISSING IN PRIVATE LIST: ");
        //test1->print();
        missing = 1;
        VarItem* var = test1->getFirst();
        CVarEntryInfo* syb = var->var->Clone();
        int change_fid = var->file_id;
        test1->remove(var->var);
        int stored_fid = SwitchFile(change_fid);
        if (syb->GetVarType() != VAR_REF_ARRAY_EXP) {
#if __SPF
            const wchar_t* rus = R162;
            Note("add private scalar '%s'", rus, syb->GetSymbol()->identifier(), PRIVATE_ANALYSIS_ADD_VAR, lstart->getPrivateListStatement());
#else
            Warning("var '%s' was added to private list", syb->GetSymbol()->identifier(), PRIVATE_ANALYSIS_ADD_VAR, lstart->getPrivateListStatement());
#endif
            SgExprListExp* nls = new SgExprListExp();
            SgVarRefExp* nvr = new SgVarRefExp(syb->GetSymbol());
            nls->setLhs(nvr);
            nls->setRhs(prl->lhs());
            prl->setLhs(nls);
        }
        else 
        {
            CArrayVarEntryInfo* tt = (CArrayVarEntryInfo*)syb;
            if (tt->HasActiveElements()) 
            {
#if __SPF
                const wchar_t* rus = R163;
                Note("add private array '%s'", rus, syb->GetSymbol()->identifier(), PRIVATE_ANALYSIS_ADD_VAR, lstart->getPrivateListStatement());
#else
                Warning("var '%s' was added to private list", syb->GetSymbol()->identifier(), PRIVATE_ANALYSIS_ADD_VAR, lstart->getPrivateListStatement());
#endif

// TODO: need to check all situation before commit it to release 
#if !__SPF
                SgExprListExp *nls = new SgExprListExp();
                SgArrayRefExp *nvr = new SgArrayRefExp(*syb->GetSymbol());
                nls->setLhs(nvr);
                nls->setRhs(prl->lhs());
                prl->setLhs(nls);
#endif
            }
        }
        delete(syb);
        SwitchFile(stored_fid);
        
        /*printf("modified parallel stmt:\n");
        prs->unparsestdout();
        printf("\n");*/
    }
    if (extra == 0 && missing == 0) {
#if ACCAN_DEBUG
        Warning("Correct", "", 0, lstart->getPrivateListStatement());
#endif
    }
    //printf("PRIVATE VARS: ");
    //detected->print();
    //printf("DECLARATION: ");
    //p_pri->print();
    //printf("LAST PRIVATE VARS: ");
    //lp->print();
    if (test1)
        delete test1;
    

    if (test2)
        delete test2;
    
    if (detected)
        delete detected;
    
    if (original)
        delete original;
    
    if (lp)
        delete lp;
    
    SwitchFile(stored_fid);
}
//#endif

ControlFlowItem* doLoops::checkStatementForLoopEnding(int label, ControlFlowItem* last)
{

    if (current == NULL || label == -1 || label != current->getLabel())
        return last;
    return checkStatementForLoopEnding(label, endLoop(last));
}

doLoopItem* doLoops::findLoop(SgSymbol* s)
{
    doLoopItem* l = first;
    while (l != NULL){
        if (l->getName() == s)
            return l;
        l = l->getNext();
    }
    return NULL;
}

void doLoops::addLoop(int l, SgSymbol* s, ControlFlowItem* i, ControlFlowItem* e)
{
    doLoopItem* nl = new doLoopItem(l, s, i, e);
    if (first == NULL)
        first = current = nl;
    else{
        current->setNext(nl);
        nl->HandleNewItem(current);
        current = nl;
    }
}

ControlFlowItem* doLoops::endLoop(ControlFlowItem* last)
{
    doLoopItem* removed = current;
    if (first == current)
        first = current = NULL;
    else{
        doLoopItem* prev = first;
        while (prev->getNext() != current)
            prev = prev->getNext();
        prev->setNext(NULL);
        current = prev;
    }
    last->AddNextItem(removed->getSourceForCycle());
    ControlFlowItem* empty = removed->getSourceForExit();
    delete removed;
    return empty;
}

VarSet* ControlFlowGraph::getPrivate()
{
    //printControlFlowList(first->getStart(), last->getStart());
    if (pri == NULL)
    {
        bool same = false;
        int it = 0;
        CBasicBlock* p = first;
        /*
        printf("GRAPH:\n");
        while (p != NULL){
            printf("block %d: ", p->getNum());
            p->print();
            p = p->getLexNext();
        }
        */
        p = first;
        while (!same){
            p = first;
            same = true;
            while (p != NULL){
                same = p->stepMrdIn(false) && same;
                same = p->stepMrdOut(false) && same;
                p = p->getLexNext();
            }
            it++;
            //printf("iters: %d\n", it);
        }
        p = first;
        while (p != NULL) {
            p->stepMrdIn(true);
            p->stepMrdOut(true);
            //p->getMrdIn(false)->print();
            p = p->getLexNext();
        }
        
        p = first;
        VarSet* res = new VarSet();
        VarSet* loc = new VarSet();
        bool il = false;
        while (p != NULL)
        {
            res->unite(p->getUse(), false);
            loc->unite(p->getDef(), false);
            p = p->getLexNext();
        }
        //printf("USE: ");
        //res->print();
        //printf("LOC: ");
        //loc->print();
        res->unite(loc, false);
        //printf("GETUSE: ");
        //getUse()->print();

        //res->minus(getUse()); //test!
        res->minusFinalize(getUse(), true);
        pri = res;
    }
    return pri;
}

void ControlFlowGraph::liveAnalysis()
{
    bool same = false;
    int it = 0;
    CBasicBlock* p = first;
    p = first;
    while (!same){
        p = last;
        same = true;
        while (p != NULL){
            same = p->stepLVOut() && same;
            same = p->stepLVIn() && same;
            p = p->getLexPrev();
        }
        it++;
        //printf("iters: %d\n", it);
    }
}

VarSet* ControlFlowGraph::getUse()
{
    if (use == NULL)
    {
        CBasicBlock* p = first;
        VarSet* res = new VarSet();
        while (p != NULL)
        {
            VarSet* tmp = new VarSet();
            tmp->unite(p->getUse(), false);
            tmp->minus(p->getMrdIn(false));
            //printf("BLOCK %d INSTR %d USE: ", p->getNum(), p->getStart()->getStmtNo());
            //tmp->print();
            res->unite(tmp, false);
            delete tmp;
            p = p->getLexNext();
        }
        use = res;

    }
    if (!cuf)
    {
        AnalysedCallsList* call = first->getStart()->getProc();
        cuf = true;
        if (call) {
            CommonVarSet* s = pCommons->GetCommonsForVarSet(use, call);
            common_use = s;
            for (CBasicBlock* i = first; i != NULL; i = i->getLexNext()){
                for (CommonVarSet* c = i->getCommonUse(); c != NULL; c = c->next) {
                    /*
                    CommonVarSet* n = new CommonVarSet();
                    n->cvd = c->cvd;
                    n->cvd->refs++;
                    */
                    CommonVarSet* n = new CommonVarSet(*c);
                    CommonVarSet* t;
                    for (t = n; t->next != NULL; t = t->next);
                    t->next = common_use;
                    common_use = n;
                }
            }
        }
    }
    return use;
}

VarSet* ControlFlowGraph::getDef()
{
    if (def == NULL) {
        def = new VarSet();
        def->unite(last->getMrdOut(false), true);
    }
    if (!cdf)
    {
        AnalysedCallsList* call = first->getStart()->getProc();
        if (call) {
            cdf = true;
            CommonVarSet* s = pCommons->GetCommonsForVarSet(def, call);
            common_def = s;
            for (CBasicBlock* i = first; i != NULL; i = i->getLexNext()) {
                for (CommonVarSet* c = i->getCommonDef(); c != NULL; c = c->next) {
                    /*
                    CommonVarSet* n = new CommonVarSet();
                    n->cvd = c->cvd;
                    n->cvd->refs++;
                    */
                    CommonVarSet *n = new CommonVarSet(*c);
                    CommonVarSet* t;
                    for (t = n; t->next != NULL; t = t->next);
                    t->next = common_def;
                    common_def = n;
                }
            }
        }
    }
    return def;
}

CommonVarSet* CommonData::GetCommonsForVarSet(VarSet* set, AnalysedCallsList* call)
{
    CommonVarSet* res = NULL;
    for (CommonDataItem* i = list; i != NULL; i = i->next) {
        if (i->proc == call) {
            for (CommonVarInfo* v = i->info; v != NULL; v = v->next) {
                if (set->belongs(v->var)) {
                    CommonVarSet* n = new CommonVarSet();
                    n->cvd = v;
                    n->next = res;
                    res = n;
                }
            }
        }
    }
    return res;
}

void CBasicBlock::PrivateAnalysisForAllCalls()
{
    ControlFlowItem* p = start;
    while (p != NULL && (p == start || !p->isLeader())) {
        AnalysedCallsList* c = p->getCall();
        const char* oic = is_correct;
        const char* fpn = failed_proc_name;
        is_correct = NULL;
        failed_proc_name = NULL;
        if (c != NULL && c != (AnalysedCallsList*)(-1) && c != (AnalysedCallsList*)(-2) && c->header != NULL && !c->hasBeenAnalysed) {
            c->hasBeenAnalysed = true;
            
            int stored_fid = SwitchFile(c->file_id);
            
            c->graph->privateAnalyzer();
            
            SwitchFile(stored_fid);
            
        }
        is_correct = oic;
        failed_proc_name = fpn;
        p = p->getNext();
    }
    return;
}

ControlFlowItem* CBasicBlock::containsParloopEnd()
{
    ControlFlowItem* p = start;
    while (p != NULL && (p == start || !p->isLeader())){
        if (p->IsParloopEnd())
            return p;
        p = p->getNext();
    }
    return NULL;
}

ControlFlowItem* CBasicBlock::containsParloopStart()
{
    ControlFlowItem* p = start;
    while (p != NULL && (p == start || !p->isLeader())){
        if (p->IsParloopStart())
            return p;
        p = p->getNext();
    }
    return NULL;
}

void CBasicBlock::print()
{
    printf("block %d: prev: ", num);
    BasicBlockItem* p = prev;
    while (p != NULL){
        printf("%d ", p->block->num);
        p = p->next;
    }
    printf("\n");
}

ControlFlowItem* CBasicBlock::getStart()
{
    return start;
}

ControlFlowItem* CBasicBlock::getEnd()
{
    ControlFlowItem* p = start;
    ControlFlowItem* end = p;
    while (p != NULL && (p == start || !p->isLeader())){
        end = p;
        p = p->getNext();
    }
    return end;
}

VarSet* CBasicBlock::getLVOut()
{
    if (lv_out == NULL)
    {
        VarSet* res = new VarSet();
        BasicBlockItem* p = succ;
        bool first = true;
        while (p != NULL)
        {
            CBasicBlock* b = p->block;
            if (b != NULL && !b->lv_undef)
            {
                res->unite(b->getLVIn(), false);
            }
            p = p->next;
        }
        lv_out = res;
    }
    return lv_out;
}

VarSet* CBasicBlock::getLVIn()
{
    if (lv_in == NULL)
    {
        VarSet* res = new VarSet();
        res->unite(getLVOut(), false);
        res->minus(getDef());
        res->unite(getUse(), false);
        lv_in = res;
    }
    return lv_in;
}

bool CBasicBlock::IsVarDefinedAfterThisBlock(CVarEntryInfo* var, bool os)
{
    findentity = var;
    if (def->belongs(var, os)) {
        findentity = NULL;
        return true;
    }
    BasicBlockItem* p = succ;
    while (p != NULL)
    {
        CBasicBlock* b = p->block;
        if (b->ShouldThisBlockBeCheckedAgain(var) && b->IsVarDefinedAfterThisBlock(var, os)) {
            findentity = NULL;
            return true;
        }
        p = p->next;
    }
    findentity = NULL;
    return false;
}

bool CBasicBlock::stepLVOut()
{
    if (old_lv_out)
        delete old_lv_out;
    
    old_lv_out = lv_out;
    lv_out = NULL;
    getLVOut();
    lv_undef = false;
    //printf("block %d\n", num);
    //old_mrd_out->print();
    //mrd_out->print();
    return (lv_out->equal(old_lv_out));
    //return true;
}

bool CBasicBlock::stepLVIn()
{
    if (old_lv_in)
        delete old_lv_in;

    old_lv_in = lv_in;
    lv_in = NULL;
    getLVIn();
    return (lv_in->equal(old_lv_in));
    //return true;
}

VarSet* CBasicBlock::getMrdIn(bool la)
{
    if (mrd_in == NULL)
    {
        VarSet* res = new VarSet();
        BasicBlockItem* p = prev;
        bool first = true;

        while (p != NULL)
        {
            CBasicBlock* b = p->block;
            if (b != NULL && !b->undef && b->hasPrev())
            {
                if (first) {
                    res->unite(b->getMrdOut(la), la);
                    first = false;
                }
                else
                    res->intersect(b->getMrdOut(la), la, true);
            }
            p = p->next;
        }
        mrd_in = res;
    }
    return mrd_in;
}

bool CBasicBlock::hasPrev()
{
    return prev_status == 1;
}

VarSet* CBasicBlock::getMrdOut(bool la)
{
    if (mrd_out == NULL)
    {
        VarSet* res = new VarSet();
        res->unite(getMrdIn(la), la);
        res->unite(getDef(), la);
        mrd_out = res;
        //printf("BLOCK %d INSTR %d MRDOUT: ", num, start->getStmtNo());
        //mrd_out->print();
        //print();
    }
    return mrd_out;
}

bool CBasicBlock::stepMrdOut(bool la)
{
    if (old_mrd_out)
        delete old_mrd_out;
    
    old_mrd_out = mrd_out;
    mrd_out = NULL;
    getMrdOut(la);
    undef = false;
    //printf("block %d\n", num);
    //old_mrd_out->print();
    //mrd_out->print();
    return (mrd_out->equal(old_mrd_out));
    //return true;
}

bool CBasicBlock::stepMrdIn(bool la)
{
    if (old_mrd_in)
        delete old_mrd_in;
    
    old_mrd_in = mrd_in;
    mrd_in = NULL;
    getMrdIn(la);
    return (mrd_in->equal(old_mrd_in));
    //return true;
}

bool IsPresentInExprList(SgExpression* ex, CExprList* lst)
{
    while (lst != NULL) {
        if (lst->entry == ex)
            return true;
        lst = lst->next;
    }
    return false;
}

CRecordVarEntryInfo* AddRecordVarRef(SgRecordRefExp* ref)
{
    if (isSgRecordRefExp(ref->lhs())) {
        CVarEntryInfo* parent = AddRecordVarRef(isSgRecordRefExp(ref->lhs()));
        if (parent)
            return new CRecordVarEntryInfo(ref->rhs()->symbol(), parent);
        return NULL;
    }
    if (isSgVarRefExp(ref->lhs())) {
        CVarEntryInfo* parent = new CScalarVarEntryInfo(isSgVarRefExp(ref->lhs())->symbol());
        return new CRecordVarEntryInfo(ref->rhs()->symbol(), parent);
    }
    if (isSgArrayRefExp(ref->lhs())) {
        CVarEntryInfo* parent = new CArrayVarEntryInfo(isSgArrayRefExp(ref->lhs())->symbol(), isSgArrayRefExp(ref->lhs()));
        return new CRecordVarEntryInfo(ref->rhs()->symbol(), parent);
    }
    return NULL;
}

void CBasicBlock::AddOneExpressionToUse(SgExpression* ex, SgStatement* st, CArrayVarEntryInfo* v)
{
    CVarEntryInfo* var = NULL;
    SgVarRefExp* r;
    if ((r = isSgVarRefExp(ex)))
        var = new CScalarVarEntryInfo(r->symbol());
    SgArrayRefExp* ar;
    if ((ar = isSgArrayRefExp(ex))) {
        if (!v)
            var = new CArrayVarEntryInfo(ar->symbol(), ar);
        else {
            var = v->Clone();
            var->SwitchSymbol(ar->symbol());
        }
    }
    SgRecordRefExp* rr;
    if ((rr = isSgRecordRefExp(ex)))
        var = AddRecordVarRef(rr);
    if (var) {
        var->RegisterUsage(def, use, st);
        delete var;
    }
}

void CBasicBlock::AddOneExpressionToDef(SgExpression* ex, SgStatement* st, CArrayVarEntryInfo* v)
{
    CVarEntryInfo* var = NULL;
    SgVarRefExp* r;
    if ((r = isSgVarRefExp(ex)))
        var = new CScalarVarEntryInfo(r->symbol());
    SgRecordRefExp* rr;
    if ((rr = isSgRecordRefExp(ex)))
        var = AddRecordVarRef(rr);
    SgArrayRefExp* ar;
    if ((ar = isSgArrayRefExp(ex))) {
        if (!v)
            var = new CArrayVarEntryInfo(ar->symbol(), ar);
        else {
            var = v->Clone();
            var->SwitchSymbol(ar->symbol());
        }
    }
    if (var) {
        var->RegisterDefinition(def, use, st);
        delete var;
    }
}

void CBasicBlock::addExprToUse(SgExpression* ex, CArrayVarEntryInfo* v = NULL, CExprList* lst = NULL)
{
    if (ex != NULL)
    {
        CExprList* cur = new CExprList();
        cur->entry = ex;
        cur->next = lst;
        SgFunctionCallExp* f = isSgFunctionCallExp(ex);
        if (!f) {
            if (!IsPresentInExprList(ex->lhs(), cur))
                addExprToUse(ex->lhs(), v, cur);
            if (!isSgUnaryExp(ex))
                if (!IsPresentInExprList(ex->rhs(), cur))
                    addExprToUse(ex->rhs(), v, cur);
            AddOneExpressionToUse(ex, NULL, v);
        }
        delete cur;
        /*
        SgVarRefExp* r;
        //printf(" %s\n", f->funName()->identifier());
        bool intr = isIntrinsicFunctionNameACC(f->funName()->identifier()) && !IsUserFunctionACC(f->funName());
        bool pure = IsPureProcedureACC(f->funName());
        if (!intr && !pure){
            printf("function not intristic or pure: %s\n", f->funName()->identifier());
            is_correct = false;
            return;
        }
        if (intr) {
            ProcessIntristicProcedure(true, f->numberOfArgs(), f);
            return;
        }
        ProcessProcedureHeader(true, isSgProcHedrStmt(GRAPHNODE(f->funName())->st_header), f);
        */
    }
}

void CBasicBlock::ProcessIntrinsicProcedure(bool isF, int narg, void* f, const char* name)
{
    for (int i = 0; i < narg; i++) {
        SgExpression* ar = GetProcedureArgument(isF, f, i);
        if (IsAnIntrinsicSubroutine(name)) 
        {
            SgExpression* v = CheckIntrinsicParameterFlag(name, i, ar, INTRINSIC_IN);
            if (v)
                addExprToUse(v);            
        }
        else
            addExprToUse(ar);
        
        AddOneExpressionToDef(CheckIntrinsicParameterFlag(name, i, ar, INTRINSIC_OUT), NULL, NULL);
    }
}

void CBasicBlock::ProcessProcedureWithoutBody(bool isF, void* f, bool out)
{
    for (int i = 0; i < GetNumberOfArguments(isF, f); i++){
        addExprToUse(GetProcedureArgument(isF, f, i));
        if (out)
            AddOneExpressionToDef(GetProcedureArgument(isF, f, i), NULL, NULL);
    }
}

SgSymbol* CBasicBlock::GetProcedureName(bool isFunc, void* f)
{
    if (isFunc) {
        SgFunctionCallExp* fc = (SgFunctionCallExp*)f;
        return fc->funName();
    }
    SgCallStmt* pc = (SgCallStmt*)f;
    return pc->name();
}

int GetNumberOfArguments(bool isF, void* f)
{
    if (isF) {
        SgFunctionCallExp* fc = (SgFunctionCallExp*)f;
        return fc->numberOfArgs();
    }
    SgCallStmt* pc = (SgCallStmt*)f;
    return pc->numberOfArgs();
}

SgExpression* GetProcedureArgument(bool isF, void *f, const int i)
{
    SgExpression *arg = NULL;
    if (isF)
    {
        SgFunctionCallExp* fc = (SgFunctionCallExp*)f;
        arg = fc->arg(i);
    }
    else
    {
        SgCallStmt *pc = (SgCallStmt*)f;
        arg = pc->arg(i);
    }
    return arg;
}

void CBasicBlock::ProcessProcedureHeader(bool isF, SgProcHedrStmt *header, void *f, const char* name)
{   
    if (!header) 
    {
        is_correct = "no header found";
        failed_proc_name = name;
        return;
    }
    
    for (int i = 0; i < header->numberOfParameters(); ++i) 
    {
        int stored = SwitchFile(header->getFileId());
        SgSymbol *arg = header->parameter(i);
        SwitchFile(stored);

        if (arg->attributes() & (IN_BIT)) 
        {
            SgExpression *ar = GetProcedureArgument(isF, f, i);
            addExprToUse(ar);
        }        
        else if (arg->attributes() & (INOUT_BIT)) 
        {
            addExprToUse(GetProcedureArgument(isF, f, i));
            AddOneExpressionToDef(GetProcedureArgument(isF, f, i), NULL, NULL);
        }
        else if (arg->attributes() & (OUT_BIT))
            AddOneExpressionToDef(GetProcedureArgument(isF, f, i), NULL, NULL);
        else 
        {
            is_correct = "no bitflag set for pure procedure";
            break;
        }
    }    
}

bool AnalysedCallsList::isArgIn(int i, CArrayVarEntryInfo** p)
{
    int stored = SwitchFile(this->file_id);
    SgProcHedrStmt* h = isSgProcHedrStmt(header);
    VarSet* use = graph->getUse();
    SgSymbol* par = h->parameter(i);
    /*
    CScalarVarEntryInfo* var = new CScalarVarEntryInfo(par);
    bool result = false;
    if (use->belongs(var))
        result = true;
    delete var;
    */
    VarItem* result = use->belongs(par);
    if (result && result->var->GetVarType() == VAR_REF_ARRAY_EXP && p) 
        *p = (CArrayVarEntryInfo*)result->var;
    SwitchFile(stored);

    return result;
}

bool AnalysedCallsList::isArgOut(int i, CArrayVarEntryInfo** p)
{
    int stored = SwitchFile(this->file_id);
    SgProcHedrStmt* h = isSgProcHedrStmt(header);
    graph->privateAnalyzer();
    VarSet* def = graph->getDef();
    SgSymbol* par = h->parameter(i);
    /*
    CScalarVarEntryInfo* var = new CScalarVarEntryInfo(par);
    bool result = false;
    if (def->belongs(var))
        result = true;
    delete var;
    */
    VarItem* result = def->belongs(par);
    if (result && result->var->GetVarType() == VAR_REF_ARRAY_EXP && p) 
        *p = (CArrayVarEntryInfo*)result->var;
    SwitchFile(stored);

    return result;
}

void CommonData::MarkAsUsed(VarSet* use, AnalysedCallsList* lst)
{
    for (CommonDataItem* it = list; it != NULL; it = it->next) {
        if (it->proc == lst) {
            for (CommonVarInfo* v = it->info; v != NULL; v = v->next) {
                CVarEntryInfo* r = v->var;
                if (use->belongs(r))
                    v->isInUse = true;
            }
        }
    }
}

void CBasicBlock::ProcessUserProcedure(bool isFun, void* call, AnalysedCallsList* c)
{
    /*
    if (c == NULL || c->graph == NULL) {
        is_correct = "no body found for procedure";
        if (c != NULL)
            failed_proc_name = c->funName;
        else
            failed_proc_name = NULL;
        return;
    }
    */
    if (c != (AnalysedCallsList*)(-1) && c != (AnalysedCallsList*)(-2) && c != NULL && c->graph != NULL) 
    {
        int stored_file_id = SwitchFile(c->file_id);
        c->graph->getPrivate(); //all sets actually
        SgStatement *cp = c->header->controlParent();
        SwitchFile(stored_file_id);

        if (proc && proc->header->variant() == PROC_HEDR && cp == proc->header) {
            VarSet* use_c = new VarSet();
            use_c->unite(c->graph->getUse(), false);
            for (VarItem* exp = use_c->getFirst(); exp != NULL; exp = use_c->getFirst()) {
                if (exp->var->GetSymbol()->scope() == proc->header) {
                    addExprToUse(new SgVarRefExp(exp->var->GetSymbol())); // TESTING
                }
                use_c->remove(exp->var);
            }
            delete use_c;
            VarSet* def_c = new VarSet();
            def_c->unite(c->graph->getDef(), true);
            for (VarItem* exp = def_c->getFirst(); exp != NULL; exp = def_c->getFirst()) {
                if (exp->var->GetSymbol()->scope() == proc->header) {
                    def->addToSet(exp->var, NULL);
                }
                def_c->remove(exp->var);
            }
            delete def_c;
        }

        pCommons->MarkAsUsed(c->graph->getUse(), c);
        SgProcHedrStmt* header = isSgProcHedrStmt(c->header);
        if (!header) {
            is_correct = "no header for procedure";
            failed_proc_name = c->funName;
            return;
        }
    }

    for (int i = 0; i < GetNumberOfArguments(isFun, call); i++) 
    {
        SgExpression* ar = GetProcedureArgument(isFun, call, i);
        CArrayVarEntryInfo* tp = NULL;
        if (c == (AnalysedCallsList*)(-1) || c == (AnalysedCallsList*)(-2) || c == NULL || c->graph == NULL || c->isArgIn(i, &tp))
            addExprToUse(ar, tp);
        tp = NULL;
        if (c == (AnalysedCallsList*)(-1) || c == NULL || c->graph == NULL || c->isArgOut(i, &tp))
            AddOneExpressionToDef(GetProcedureArgument(isFun, call, i), NULL, tp);
    }

    if (c != (AnalysedCallsList*)(-1) && c != (AnalysedCallsList*)(-2) && c != NULL && c->graph != NULL) {
        for (CommonVarSet* cu = c->graph->getCommonUse(); cu != NULL; cu = cu->next) {
            CommonVarInfo* v = cu->cvd;
            AnalysedCallsList* tp = start->getProc();
            CommonDataItem* p = v->parent;
            if (CommonDataItem* it = pCommons->IsThisCommonUsedInProcedure(p, tp)) {
                if (pCommons->CanHaveNonScalarVars(it))
                    continue;
                CommonVarInfo* i = it->info;
                CommonVarInfo* j = p->info;
                while (j != v) {
                    j = j->next;
                    if (i)
                        i = i->next;
                    else
                        continue;
                }
                if (!i)
                    continue;
                SgVarRefExp* var = new SgVarRefExp(i->var->GetSymbol());
                addExprToUse(var);
            }
            else {
                common_use = new CommonVarSet(*cu);
            }
        }
        for (CommonVarSet* cd = c->graph->getCommonDef(); cd != NULL; cd = cd->next) {
            CommonVarInfo* v = cd->cvd;
            AnalysedCallsList* tp = start->getProc();
            CommonDataItem* p = v->parent;
            if (CommonDataItem* it = pCommons->IsThisCommonUsedInProcedure(p, tp)) {
                if (pCommons->CanHaveNonScalarVars(it))
                    continue;
                CommonVarInfo* i = it->info;
                CommonVarInfo* j = p->info;
                while (j != v) {
                    j = j->next;
                    if (i)
                        i = i->next;
                }
                if (!i)
                    continue;
                def->addToSet(i->var, NULL);
            }
            else {
                common_def = new CommonVarSet(*cd);
            }
        }
    }

}

bool CommonData::CanHaveNonScalarVars(CommonDataItem* item)
{
    for (CommonDataItem* it = list; it != NULL; it = it->next) {
        if (it->name == item->name && it->first == item->first && !it->onlyScalars)
            return true;
    }
    bool res = !item->onlyScalars;
    //printf("CommonData::CanHaveNonScalarVars: %d\n", res);
    return res;
}

CommonDataItem* CommonData::IsThisCommonUsedInProcedure(CommonDataItem* item, AnalysedCallsList* p)
{
    for (CommonDataItem* it = list; it != NULL; it = it->next) {
        if (it->proc == p) {
            if (it->name == item->name)
                return it;
        }
    }
    return NULL;
}

void CBasicBlock::setDefAndUse()
{
    ControlFlowItem* p = start;
    while (p != NULL && (p == start || !p->isLeader()))
    {
        if (p->getJump() == NULL)
        {
            SgStatement* st = p->getStatement();
            SgFunctionCallExp* f = p->getFunctionCall();
            
            if (f != NULL)
            {
                bool add_intr = IsAnIntrinsicSubroutine(f->funName()->identifier()) != NULL; // strcmp(f->funName()->identifier(), "date_and_time") == 0;
                bool intr = (isIntrinsicFunctionNameACC(f->funName()->identifier()) || add_intr) && !IsUserFunctionACC(f->funName());
                bool pure = IsPureProcedureACC(f->funName());
                AnalysedCallsList* c = p->getCall();
                if (!intr && !pure && c && c != (AnalysedCallsList*)(-1) && c != (AnalysedCallsList*)(-2) && !(c->IsIntrinsic())) {

                    if (c->header == NULL) {
                        is_correct = "no header for procedure";
                        failed_proc_name = c->funName;
                    }
                    else {
                        //graph_node* oldgn = currentGraphNode;
                        //graph_node* newgn = GRAPHNODE(f->funName())->file_id;
                        //currentGraphNode = newgn;
                        ProcessUserProcedure(true, f, c);
                        //currentGraphNode = oldgn;

                    }
                }
                else if (c == (AnalysedCallsList*)(-1) || c == (AnalysedCallsList*)(-2))
                    ProcessProcedureWithoutBody(true, f, c == (AnalysedCallsList*)(-1));
                else if (intr || (c && c->IsIntrinsic())) {
                    ProcessIntrinsicProcedure(true, f->numberOfArgs(), f, f->funName()->identifier());
                }else
                    ProcessProcedureHeader(true, isSgProcHedrStmt(GRAPHNODE(f->funName())->st_header), f, f->funName()->identifier());
            }


            if (st != NULL)
            {
                switch (st->variant())
                {
                case ASSIGN_STAT:
                    {
                        SgAssignStmt* s = isSgAssignStmt(st);
                        SgExpression* l = s->lhs();
                        SgExpression* r = s->rhs();
                        addExprToUse(r);
                        AddOneExpressionToDef(l, st, NULL);
                        break;
                    }
                case PRINT_STAT:
                case WRITE_STAT:
                case READ_STAT:
                    {
                        SgInputOutputStmt* s = isSgInputOutputStmt(st);
                        if (s) {
                            SgExpression* ex = s->itemList();
                            while (ex && ex->lhs()) {
                                if (st->variant() == READ_STAT) {
                                    AddOneExpressionToDef(ex->lhs(), st, NULL);
                                }
                                else {
                                    addExprToUse(ex->lhs());
                                }
                                ex = ex->rhs();
                            }
                        }
                        break;
                    }
                case PROC_STAT:
                {
                    SgCallStmt* f = isSgCallStmt(st);
                    bool add_intr = IsAnIntrinsicSubroutine(f->name()->identifier()) != NULL;
                    bool intr = (isIntrinsicFunctionNameACC(f->name()->identifier()) || add_intr) && !IsUserFunctionACC(f->name());
                    bool pure = IsPureProcedureACC(f->name());
                    if (!intr && !pure) {
                        AnalysedCallsList* c = p->getCall();
                        //graph_node* oldgn = currentGraphNode;
                        //graph_node* newgn = GRAPHNODE(f->name());
                        //currentGraphNode = newgn;
                        ProcessUserProcedure(false, f, c);
                        //currentGraphNode = oldgn;
                        break;
                    }
                    if (intr) {
                        ProcessIntrinsicProcedure(false, f->numberOfArgs(), f, f->name()->identifier());
                        break;
                    }
                    ProcessProcedureHeader(false, isSgProcHedrStmt(GRAPHNODE(f->name())->st_header), f, f->name()->identifier());
                }
                default:
                    break;
                }
            }
        }
        else
            addExprToUse(p->getExpression());
            p = p->getNext();
    }
}

VarSet* CBasicBlock::getDef()
{
    if (def == NULL)
    {
        def = new VarSet();
        use = new VarSet();
        setDefAndUse();
    }
    return def;
}

VarSet* CBasicBlock::getUse()
{
    if (use == NULL)
    {
        use = new VarSet();
        def = new VarSet();
        setDefAndUse();
    }
    return use;
}

#ifdef __SPF
template<typename IN_TYPE, typename OUT_TYPE>
const vector<OUT_TYPE> getAttributes(IN_TYPE st, const set<int> dataType);
#endif

DoLoopDataItem* DoLoopDataList::FindLoop(SgStatement* st)
{
    DoLoopDataItem* it = list;
    while (it != NULL) {
        if (it->statement == st)
            return it;
        it = it->next;
    }
    return NULL;
}

bool GetExpressionAndCoefficientOfBound(SgExpression* exp, SgExpression** end, int* coef)
{
    if (exp->variant() == SUBT_OP) {
        if (exp->rhs() && exp->rhs()->variant() == INT_VAL) {
            *end = exp->lhs();
            *coef = -exp->rhs()->valueInteger();
            return true;
        }
    }
    if (exp->variant() == ADD_OP) {
        if (exp->lhs() && exp->lhs()->variant() == INT_VAL) {
            *end = exp->rhs();
            *coef = exp->lhs()->valueInteger();
            return true;
        }
        if (exp->rhs() && exp->rhs()->variant() == INT_VAL) {
            *end = exp->lhs();
            *coef = exp->lhs()->valueInteger();
            return true;
        }
    }
    return false;
}

CArrayVarEntryInfo::CArrayVarEntryInfo(SgSymbol* s, SgArrayRefExp* r) : CVarEntryInfo(s)
{
#if __SPF
    addToCollection(__LINE__, __FILE__, this, 16);
#endif
    // TODO: need to check all alhorithm!!
    disabled = true;

    if (!r)
        subscripts = 0;
    else
        subscripts = r->numberOfSubscripts();
    if (subscripts)
        data.resize(subscripts);    

    for (int i = 0; i < subscripts; i++) 
    {
        data[i].defined = false;
        data[i].bound_modifiers[0] = data[i].bound_modifiers[1] = 0;
        data[i].step = 1;
        data[i].left_bound = data[i].right_bound = NULL;
        data[i].coefs[0] = data[i].coefs[1] = 0;
        data[i].loop = NULL;
#if __SPF
        const vector<int*> coefs = getAttributes<SgExpression*, int*>(r->subscript(i), set<int>{ INT_VAL });
        const vector<SgStatement*> fs = getAttributes<SgExpression*, SgStatement*>(r->subscript(i), set<int>{ FOR_NODE });
        if (fs.size() == 1) 
        {
            if (data[i].loop != NULL) 
            {
                if (coefs.size() == 1) 
                {
                    data[i].defined = true;
                    data[i].bound_modifiers[0] = data[i].bound_modifiers[1] = coefs[0][1];
                    data[i].coefs[0] = coefs[0][0];
                    data[i].coefs[1] = coefs[0][1];
                    data[i].step = coefs[0][0];
                    int tmp;

                    SgExpression *et;
                    if (GetExpressionAndCoefficientOfBound(data[i].loop->l, &et, &tmp)) 
                    {
                        data[i].left_bound = et;
                        data[i].bound_modifiers[0] += tmp;
                    }
                    else 
                        data[i].left_bound = data[i].loop->l;
                    
                    if (GetExpressionAndCoefficientOfBound(data[i].loop->r, &et, &tmp)) 
                    {
                        data[i].right_bound = et;
                        data[i].bound_modifiers[1] += tmp;
                    }
                    else 
                        data[i].right_bound = data[i].loop->r;                    
                }
            }
        }
#endif
        if (!data[i].defined) 
        {
            SgExpression* ex = r->subscript(i);
            if (ex->variant() == INT_VAL) 
            {
                data[i].bound_modifiers[0] = ex->valueInteger();
                data[i].bound_modifiers[1] = ex->valueInteger();
                data[i].defined = true;
            }
            else 
            {
                data[i].bound_modifiers[0] = 0;
                data[i].bound_modifiers[1] = 0;
                data[i].left_bound = data[i].right_bound = ex;
                data[i].defined = true;
            }
        }
    }
}

CArrayVarEntryInfo::CArrayVarEntryInfo(SgSymbol *s, int sub, int ds, const vector<ArraySubscriptData> &d) 
                                       : CVarEntryInfo(s), subscripts(sub), disabled(ds)
{ 
#if __SPF
    addToCollection(__LINE__, __FILE__, this, 16);
#endif
    if (sub > 0) 
        data = d;
}

VarItem* VarSet::GetArrayRef(CArrayVarEntryInfo* info)
{
    VarItem* it = list;
    while (it != NULL) {
        CVarEntryInfo* v = it->var;
        if (v->GetVarType() == VAR_REF_ARRAY_EXP) {
            if (OriginalSymbol(info->GetSymbol()) == OriginalSymbol(v->GetSymbol()))
                return it;
        }
        it = it->next;
    }
    return NULL;
}

void CArrayVarEntryInfo::RegisterUsage(VarSet *def, VarSet *use, SgStatement *st)
{
    VarItem *it = def->GetArrayRef(this);
    CArrayVarEntryInfo *add = this;
    if (it != NULL) 
        add = *this - *(CArrayVarEntryInfo*)(it->var);
    
    if (use != NULL && add != NULL && add->HasActiveElements()) 
        use->addToSet(add, st);
    
    if (add != this)
        delete add;
}

CArrayVarEntryInfo& CArrayVarEntryInfo::operator-=(const CArrayVarEntryInfo& b)
{
    if (subscripts == 0)
    {
        if (b.HasActiveElements()) 
            disabled = true;        
        return *this;
    }

    if (b.subscripts == 0) 
    {
        if (HasActiveElements()) 
            MakeInactive();        
        return *this;
    }

    if (subscripts != b.subscripts || !data.size() || !b.data.size() || !(data[0].defined) || !(b.data[0].defined)) 
        return *this;
    
    for (int i = 0; i < subscripts; i++) 
    {
        if (b.data[i].left_bound == NULL) 
        {
            if (data[i].left_bound && data[i].left_bound->variant() == INT_VAL) 
            {
                if (data[i].left_bound->valueInteger() + data[i].bound_modifiers[0] == b.data[i].bound_modifiers[0]) 
                {
                    data[i].bound_modifiers[0]++;
                    continue;
                }
            }
        }

        if (data[i].left_bound == NULL && b.data[i].left_bound == NULL &&
            data[i].right_bound == NULL && b.data[i].right_bound == NULL) 
        {
            if (data[i].bound_modifiers[0] < b.data[i].bound_modifiers[0]) 
            {
                data[i].bound_modifiers[1] = b.data[i].bound_modifiers[0] - 1;
                continue;
            }

            if (data[i].bound_modifiers[1] > b.data[i].bound_modifiers[1]) 
            {
                data[i].bound_modifiers[0] = b.data[i].bound_modifiers[1] + 1;
                continue;
            }
            data[i].defined = false;
        }

        if (data[i].left_bound == b.data[i].left_bound && data[i].bound_modifiers[0] < b.data[i].bound_modifiers[0]) 
        {
            data[i].bound_modifiers[0] = data[i].bound_modifiers[0];
            data[i].bound_modifiers[1] = b.data[i].bound_modifiers[0] - 1;
            data[i].right_bound = data[i].left_bound;
        }

        if (data[i].right_bound == b.data[i].right_bound && data[i].bound_modifiers[1] > b.data[i].bound_modifiers[1]) 
        {
            data[i].bound_modifiers[0] = b.data[i].bound_modifiers[1] + 1;
            data[i].bound_modifiers[1] = data[i].bound_modifiers[1];
            data[i].left_bound = data[i].right_bound;
        }

        if (b.data[i].left_bound == NULL && b.data[i].right_bound == NULL && 
            (data[i].left_bound != NULL || data[i].right_bound != NULL))
            continue;        
        else 
        {
            data[i].bound_modifiers[0] = data[i].bound_modifiers[1] = 0;
            data[i].left_bound = NULL;
            data[i].right_bound = NULL;
            data[i].defined = false;
            //empty set
        }
    }
    return *this;
}

CArrayVarEntryInfo* operator-(const CArrayVarEntryInfo& a, const CArrayVarEntryInfo& b)
{
    //return NULL;
    CArrayVarEntryInfo* nv = (CArrayVarEntryInfo*)a.Clone();
    *nv -= b;
    return nv;
}

CArrayVarEntryInfo* operator+(const CArrayVarEntryInfo& a, const CArrayVarEntryInfo& b)
{
    CArrayVarEntryInfo* nv = (CArrayVarEntryInfo*)a.Clone();
    *nv += b;
    return nv;
}

void CArrayVarEntryInfo::RegisterDefinition(VarSet* def, VarSet* use, SgStatement* st)
{
    def->addToSet(this, st);
    use->PossiblyAffectArrayEntry(this);
}

void VarSet::PossiblyAffectArrayEntry(CArrayVarEntryInfo* var)
{
    VarItem* it = GetArrayRef(var);
    if (!it)
        return;
    ((CArrayVarEntryInfo*)(it->var))->ProcessChangesToUsedEntry(var);
}

void CArrayVarEntryInfo::ProcessChangesToUsedEntry(CArrayVarEntryInfo* var)
{
    if (disabled || var->disabled || subscripts != var->subscripts)
        return;
    for (int i = 0; i < subscripts; i++) 
    {
        if (!data[i].defined)
            continue;

        if (data[i].loop == var->data[i].loop && data[i].loop != NULL) 
        {
            if (data[i].coefs[0] == var->data[i].coefs[0])
            {
                if (data[i].coefs[1] < var->data[i].coefs[1]) 
                {
                    if (data[i].left_bound && data[i].left_bound->variant() == INT_VAL) 
                    {
                        data[i].bound_modifiers[0] = data[i].left_bound->valueInteger() + data[i].bound_modifiers[0];
                        data[i].bound_modifiers[1] = data[i].left_bound->valueInteger() + var->data[i].coefs[1] - 1;
                        data[i].left_bound = data[i].right_bound = NULL;
                    }
                    else 
                    {
                        //maybe add something, not sure
                    }
                }
            }
        }
    }
}

CArrayVarEntryInfo& CArrayVarEntryInfo::operator*=(const CArrayVarEntryInfo& b)
{
    if (subscripts == 0)
    {
        if (b.HasActiveElements())
            disabled = true;
        return *this;
    }

    if (b.subscripts == 0)
    {
        if (HasActiveElements())
            MakeInactive();
        return *this;
    }

    //return *this;
    if (subscripts != b.subscripts || subscripts == 0 || b.subscripts == 0 || !data.size() || !b.data.size() || !(data[0].defined) || !(b.data[0].defined)) 
        return *this;
    
    for (int i = 0; i < subscripts; i++) 
    {
        if (b.disabled) 
            data[i].left_bound = data[i].right_bound = NULL;
        
        if (data[i].left_bound == b.data[i].left_bound) 
            data[i].bound_modifiers[0] = std::max(data[i].bound_modifiers[0], b.data[i].bound_modifiers[0]);
        
        if (data[i].right_bound == b.data[i].right_bound) 
            data[i].bound_modifiers[1] = std::min(data[i].bound_modifiers[1], b.data[i].bound_modifiers[1]);        
    }
    return *this;
}

CArrayVarEntryInfo& CArrayVarEntryInfo::operator+=(const CArrayVarEntryInfo& b)
{
    if (subscripts == 0)
    {
        if (b.HasActiveElements())
            disabled = true;
        return *this;
    }

    if (b.subscripts == 0)
    {
        if (HasActiveElements())
            MakeInactive();
        return *this;
    }

    //return *this;
    if (disabled && !b.disabled && b.data.size()) 
    {
        for (int i = 0; i < subscripts; i++)
            data[i] = b.data[i];
        disabled = false;
        return *this;
    }

    if (subscripts != b.subscripts || subscripts == 0 || b.subscripts == 0 || !data.size() || !b.data.size() || disabled || b.disabled) 
        return *this;
    
    for (int i = 0; i < subscripts; i++) 
    {

        if (data[i].left_bound == b.data[i].left_bound) 
            data[i].bound_modifiers[0] = std::min(data[i].bound_modifiers[0], b.data[i].bound_modifiers[0]);
        
        if (data[i].right_bound == b.data[i].right_bound) 
            data[i].bound_modifiers[1] = std::max(data[i].bound_modifiers[1], b.data[i].bound_modifiers[1]);
        
        if (data[i].left_bound == NULL && data[i].right_bound == NULL && (b.data[i].left_bound != NULL || b.data[i].right_bound != NULL)) 
        {
            const ArraySubscriptData &tmp = data[i];
            data[i] = b.data[i];
            if (data[i].left_bound && data[i].left_bound->variant() == INT_VAL) 
            {
                if (tmp.bound_modifiers[1] == data[i].left_bound->valueInteger() + data[i].bound_modifiers[0] - 1) 
                    data[i].bound_modifiers[0] -= (1 + tmp.bound_modifiers[1] - tmp.bound_modifiers[0]);
                
            }

            if (data[i].right_bound && data[i].right_bound->variant() == INT_VAL) 
            {
                if (tmp.bound_modifiers[0] == data[i].left_bound->valueInteger() + data[i].bound_modifiers[1] + 1) 
                    data[i].bound_modifiers[1] += (1 + tmp.bound_modifiers[1] - tmp.bound_modifiers[0]);                
            }
        }
    }
    return *this;
}

void VarSet::RemoveDoubtfulCommonVars(AnalysedCallsList* call)
{
    VarItem* it = list;
    VarItem* prev = NULL;
    while (it != NULL) {
        CommonDataItem* d = pCommons->IsThisCommonVar(it, call);
        if (d && pCommons->CanHaveNonScalarVars(d)) {
            if (prev == NULL) {
                it = it->next;
                delete list;
                list = it;
            }
            else {
                prev->next = it->next;
                delete it;
                it = prev->next;
            }
            continue;
        }
        prev = it;
        it = it->next;
    }
}

int VarSet::count()
{
    VarItem* it = list;
    int t = 0;
    while (it != NULL) {
        it = it->next;
        t++;
    }
    return t;
}

void VarSet::LeaveOnlyRecords()
{
    VarItem* p = list;
    VarItem* prev = NULL;
    while (p != NULL) {
        if (p->var->GetVarType() == VAR_REF_RECORD_EXP) {
            CVarEntryInfo* rrec = p->var->GetLeftmostParent();
            CVarEntryInfo* old = p->var;
            if (old->RemoveReference())
                delete old;
            if (!belongs(rrec)) {
                p->var = rrec;
                prev = p;
            }
            else {
                if (prev == NULL)
                    list = list->next;
                else
                {
                    prev->next = p->next;
                    delete(p);
                    p = prev;
                }
            }
        }
        else {
            prev = p;
        }
        p = p->next;
    }
}

VarItem* VarSet::belongs(const CVarEntryInfo* var, bool os)
{
    VarItem* l = list;
    while (l != NULL)
    {
        if ((*l->var == *var))
            return l;
        if (os && OriginalSymbol(l->var->GetSymbol()) == OriginalSymbol(var->GetSymbol()))
            return l;
        l = l->next;
    }
    return NULL;
}

VarItem* VarSet::belongs(SgSymbol* s, bool os)
{
    VarItem* l = list;
    while (l != NULL)
    {
        if ((l->var->GetSymbol() == s))
            if (l->var->GetVarType() == VAR_REF_ARRAY_EXP)
                return ((CArrayVarEntryInfo*)(l->var))->HasActiveElements() ? l : NULL;
            return l;
        if (os && OriginalSymbol(l->var->GetSymbol()) == OriginalSymbol(s))
            return l;
        l = l->next;
    }
    return NULL;
}

/*
VarItem* VarSet::belongs(SgVarRefExp* var, bool os)
{
    return belongs(var->symbol(), os);
}
*/

bool VarSet::equal(VarSet* p2)
{
    if (p2 == NULL)
        return false;
    VarItem* p = list;
    VarItem* prev = NULL;
    while (p != NULL)
    {
        if (!p2->belongs(p->var) && (p->var->GetVarType() != VAR_REF_ARRAY_EXP || ((CArrayVarEntryInfo*)(p->var))->HasActiveElements()))
            return false;
        p = p->next;
    }
    p = p2->list;
    while (p != NULL) {
        if (!belongs(p->var) && (p->var->GetVarType() != VAR_REF_ARRAY_EXP || ((CArrayVarEntryInfo*)(p->var))->HasActiveElements()))
            return false;
        p = p->next;
    }
    return true;
}

void VarSet::print()
{
    VarItem* l = list;
    while (l != NULL)
    {
        if (l->var->GetVarType() != VAR_REF_ARRAY_EXP || ((CArrayVarEntryInfo*)(l->var))->HasActiveElements())
            printf("%s ", l->var->GetSymbol()->identifier());
#if PRIVATE_GET_LAST_ASSIGN
        printf("last assignments: %d\n", l->lastAssignments.size());
        for (list<SgStatement*>::iterator it = l->lastAssignments.begin(); it != l->lastAssignments.end(); it++){
            if (*it)
                printf("%s", (*it)->unparse());
        }
#endif
        l = l->next;
    }
    putchar('\n');
}

void VarSet::addToSet(CVarEntryInfo* var, SgStatement* source, CVarEntryInfo* ov)
{
    bool add = false;
    if (var->GetVarType() != VAR_REF_ARRAY_EXP) {
        VarItem* p = belongs(var, false);
        add = p == NULL;
#if PRIVATE_GET_LAST_ASSIGN
        p->lastAssignments.clear();
        p->lastAssignments.push_back(source);
#endif
        //delete p->lastAssignments;
        //p->lastAssignments = new CLAStatementItem();
        //p->lastAssignments->stmt = source;
        //p->lastAssignments->next = NULL;
    }
    else {
        CArrayVarEntryInfo* av = (CArrayVarEntryInfo*)var;
        VarItem* p = GetArrayRef(av);
        if (p == NULL)
            add = true;
        else {
            CArrayVarEntryInfo* fv = (CArrayVarEntryInfo*)p->var;
            *fv += *av;
        }
    }
    if (add) {
        VarItem* p = new VarItem();
        p->var = var->Clone();
        p->ov = ov;
        p->next = list;
        p->file_id = current_file_id;
        list = p;
    }
}

void VarSet::intersect(VarSet* set, bool la, bool array_mode = false)
{
    VarItem* p = list;
    VarItem* prev = NULL;
    while (p != NULL)
    {        
        VarItem* n = set->belongs(p->var);
        if (!n)
        {
            if (!array_mode || p->var->GetVarType() == VAR_REF_VAR_EXP) {
                if (prev == NULL)
                    list = list->next;
                else
                {
                    prev->next = p->next;
                    delete(p);
                    p = prev;
                }
            }
        }
        else {
#if PRIVATE_GET_LAST_ASSIGN
            if (la)
                p->lastAssignments.insert(p->lastAssignments.end(), n->lastAssignments.begin(), n->lastAssignments.end());
#endif
            if (p->var->GetVarType() == VAR_REF_ARRAY_EXP) {
                if (!array_mode)
                    *(CArrayVarEntryInfo*)(p->var) *= *(CArrayVarEntryInfo*)(n->var);
                else
                    *(CArrayVarEntryInfo*)(p->var) += *(CArrayVarEntryInfo*)(n->var);
            }
            prev = p;
        }
        p = p->next;
    }
    
}

VarItem* VarSet::getFirst()
{
    return list;
}

void VarSet::remove(const CVarEntryInfo* var)
{
    VarItem* p = list;
    VarItem* prev = NULL;
    while (p != NULL)
    {
        if (var == (p->var))
        {
            if (prev == NULL) {
                VarItem* t = list;
                list = list->next;
                delete(t);
                p = list;

            }
            else
            {
                prev->next = p->next;
                delete(p);
                p = prev->next;
            }
        }
        else {
            prev = p;
            p = p->next;
        }
    }
}

void VarSet::minus(VarSet* set, bool complete)
{
    VarItem* p = list;
    VarItem* prev = NULL;
    while (p != NULL)
    {
        VarItem* d = set->belongs(p->var);
        if (d && (p->var->GetVarType() != VAR_REF_ARRAY_EXP || ((CArrayVarEntryInfo*)(d->var))->HasActiveElements()))
        {
            if (p->var->GetVarType() == VAR_REF_ARRAY_EXP && !complete) {
                *(CArrayVarEntryInfo*)(p->var) -= *(CArrayVarEntryInfo*)(d->var);
                prev = p;
            }
            else if (prev == NULL)
                list = list->next;
            else
            {
                prev->next = p->next;
                delete(p);
                p = prev;
            }
        }
        else
            prev = p;

        p = p->next;
    }
}

bool VarSet::RecordBelong(CVarEntryInfo* rec) 
{
    if (rec->GetVarType() != VAR_REF_RECORD_EXP)
        return false;
    CRecordVarEntryInfo* rrec = static_cast<CRecordVarEntryInfo*>(rec);
    CVarEntryInfo* lm = rrec->GetLeftmostParent();
    VarItem* p = list;
    while (p != NULL) {
        if (*lm == *(p->var->GetLeftmostParent()))
            return true;
        p = p->next;
    }
    return false;
}

void VarSet::minusFinalize(VarSet* set, bool complete)
{
    minus(set, complete);
    VarItem* p = list;
    VarItem* prev = NULL;
    while (p != NULL)
    {
        if (set->RecordBelong(p->var)) {
            {
                if (prev == NULL)
                    list = list->next;
                else
                {
                    prev->next = p->next;
                    delete(p);
                    p = prev;
                }
            }
        }
        else
            prev = p;

        p = p->next;
    }
}

unsigned int counter = 0;

CLAStatementItem::~CLAStatementItem()
{
#if __SPF
    removeFromCollection(this);
#endif
    if (next)
        delete next;
}

CLAStatementItem* CLAStatementItem::GetLast()
{
    if (next == NULL)
        return this;
    return next->GetLast();
}

void VarSet::unite(VarSet* set, bool la)
{
    VarItem* arg2 = set->list;
    while (arg2 != NULL)
    {
        VarItem* n = belongs(arg2->var);
        if (!n)
        {
            n = new VarItem();
            if (arg2->var->GetVarType() == VAR_REF_ARRAY_EXP)
                n->var = arg2->var->Clone();
            else {
                n->var = arg2->var;
                n->var->AddReference();
            }
            n->ov = arg2->ov;
            n->next = list;
            n->file_id = arg2->file_id;
#if PRIVATE_GET_LAST_ASSIGN
            if (la)
                n->lastAssignments = arg2->lastAssignments;
#endif
            list = n;
        }
        else {
#if PRIVATE_GET_LAST_ASSIGN
            if (la) {
                //n->lastAssignments.insert(n->lastAssignments.end(), arg2->lastAssignments.begin(), arg2->lastAssignments.end());
                //n->lastAssignments.splice(n->lastAssignments.end(), arg2->lastAssignments);
                //n->lastAssignments->GetLast()->next = arg2->lastAssignments;
                n->lastAssignments = arg2->lastAssignments;
            }
#endif
            //counter++;
            //if (counter % 100 == 0)
                //printf("%d!\n", counter);
            if (n->var->GetVarType() == VAR_REF_ARRAY_EXP) {
                *(CArrayVarEntryInfo*)(n->var) += *(CArrayVarEntryInfo*)(arg2->var);
            }
        }
        arg2 = arg2->next;
    }
}



void CBasicBlock::addToPrev(CBasicBlock* bb, bool for_jump_flag, bool c, ControlFlowItem* check)
{
    BasicBlockItem* n = new BasicBlockItem();
    n->block = bb;
    n->next = prev;
    n->for_jump_flag = for_jump_flag;
    n->cond_value = c;
    n->jmp = check;
    prev = n;
}

void CBasicBlock::addToSucc(CBasicBlock* bb, bool for_jump_flag, bool c, ControlFlowItem* check)
{
    BasicBlockItem* n = new BasicBlockItem();
    n->block = bb;
    n->for_jump_flag = for_jump_flag;
    n->next = succ;
    n->cond_value = c;
    n->jmp = check;
    succ = n;
}

#if ACCAN_DEBUG

void ControlFlowItem::printDebugInfo()
{
    if (jmp == NULL && stmt == NULL && func != NULL)
        printf("FUNCTION CALL: %s\n", func->unparse());
    if (jmp == NULL)
        if (stmt != NULL)
            if (label != NULL)
                printf("%d: %s %s %s lab %4d %s", stmtNo, this->isLeader() ? "L" : " ", this->IsParloopStart() ? "S" : " ", this->IsParloopEnd() ? "E" : " ", label->id(), stmt->unparse());
            else
                printf("%d: %s %s %s          %s", stmtNo, this->isLeader() ? "L" : " ", this->IsParloopStart() ? "S" : " ", this->IsParloopEnd() ? "E" : " ", stmt->unparse());
        else
            if (label != NULL)
                printf("%d: %s %s %s lab %4d \n", stmtNo, this->isLeader() ? "L" : " ", this->IsParloopStart() ? "S" : " ", this->IsParloopEnd() ? "E" : " ", label->id());
            else
                printf("%d: %s %s %s         \n", stmtNo, this->isLeader() ? "L" : " ", this->IsParloopStart() ? "S" : " ", this->IsParloopEnd() ? "E" : " ");
    else
        if (expr == NULL)
            if (label != NULL)
                printf("%d: %s %s %s lab %4d       goto %d\n", stmtNo, this->isLeader() ? "L" : " ", this->IsParloopStart() ? "S" : " ", this->IsParloopEnd() ? "E" : " ", label->id(), jmp->getStmtNo());
            else
                printf("%d: %s %s %s                goto %d\n", stmtNo, this->isLeader() ? "L" : " ", this->IsParloopStart() ? "S" : " ", this->IsParloopEnd() ? "E" : " ", jmp->getStmtNo());
        else
            if (label != NULL)
                printf("%d: %s %s %s lab %4d       if %s goto %d\n", stmtNo, this->isLeader() ? "L" : " ", this->IsParloopStart() ? "S" : " ", this->IsParloopEnd() ? "E" : " ", label->id(), expr->unparse(), jmp->getStmtNo());
            else
                printf("%d: %s %s %s                if %s goto %d\n", stmtNo, this->isLeader() ? "L" : " ", this->IsParloopStart() ? "S" : " ", this->IsParloopEnd() ? "E" : " ", expr->unparse(), jmp->getStmtNo());
}

static void printControlFlowList(ControlFlowItem* list, ControlFlowItem* last)
{

    printf("DEBUG PRINT START\n");
    unsigned int stmtNo = 0;
    ControlFlowItem* list_copy = list;
    while (list != NULL )
    {
        list->setStmtNo(++stmtNo);
        if (list == last)
            break;
        list = list->getNext();
    }

    list = list_copy;
    while (list != NULL)
    {
        list->printDebugInfo();
        if (list == last)
            break;
        list = list->getNext();
    }
    printf("DEBUG PRINT END\n\n");
}
#endif

void CallData::printControlFlows()
{
#if ACCAN_DEBUG
    AnalysedCallsList* l = calls_list;
    while (l != NULL) {
        if (!l->isIntrinsic && l->graph != NULL && l->header != NULL) {
            ControlFlowGraph* g = l->graph;
            SgStatement* h = l->header;
            printf("CFI for %s\n\n" ,h->symbol()->identifier());
            if (g != NULL) {
                printControlFlowList(g->getCFI());
            }
            else
                printf("ERROR: DOES NOT HAVE CFI\n");
        }
        l = l->next;
    }
#endif
}
