Program Listing for File partitionedAnalysis.h

Program Listing for File partitionedAnalysis.h#

↰ Return to documentation for file (src/midend/programAnalysis/genericDataflow/analysis/partitionedAnalysis.h)

#include <featureTests.h>
#ifdef ROSE_ENABLE_SOURCE_ANALYSIS

#ifndef PARTITIONED_ANALYSIS_H
#define PARTITIONED_ANALYSIS_H

#include <sage3.h>

#include "genericDataflowCommon.h"
#include "variables.h"
#include "cfgUtils.h"
#include "analysisCommon.h"
#include "functionState.h"
#include "latticeFull.h"
#include "analysis.h"
#include "dataflow.h"
#include "VirtualCFGIterator.h"
#include "LogicalCond.h"
#include "printAnalysisStates.h"

#include <list>
#include <sstream>
#include <iostream>
#include <fstream>
#include <string>
#include <vector>

//class partition
//{
//      // The analysis that is this partition.
//      IntraPartitionDataflow* analysis;
//
//      // The current execution state of the analysis.
//      IntraPartitionDataflowCheckpoint* chkpt;
//}

class IntraPartitionDataflow;
class IntraPartitionDataflowCheckpoint;

// Set of partition dataflow analyses that were split in a given call to split.
// The original analysis that was split is explicitly identified as the "master" of the split.
class partSplit
{
        public:
        std::set<IntraPartitionDataflow*> splitSet;
        IntraPartitionDataflow* master;

        partSplit(IntraPartitionDataflow* master)
        {
                this->master = master;
                splitSet.insert(master);
        }

        void addChild(IntraPartitionDataflow* child)
        {
                splitSet.insert(child);
        }

        std::string str(std::string indent="")
        {
          std::ostringstream oss;

                oss << indent << "[partSplit:\n";
                oss << indent << "    splitSet = <";
                for(std::set<IntraPartitionDataflow*>::iterator it=splitSet.begin(); it!=splitSet.end(); )
                {
                        oss << (*it);
                        it++;
                        if(it!=splitSet.end()) oss << ", ";
                }
                oss << ">\n";
                oss << indent << "    master = "<< master << "]\n";

                return oss.str();
        }
};

class PartitionedAnalysis : virtual public IntraProceduralAnalysis
{
        // the partitions that are currently executing
        std::set<IntraPartitionDataflow*> activeParts;
        // the set of partitions that are currently blocked and need to be explicitly
        // unblocked before they may resume execution
        //std::set<IntraPartitionDataflow*> blockedParts;
        // the set of partitions that have called join and are simply waiting to be joined
        // to the master partitions that they split from
        std::set<IntraPartitionDataflow*> joinParts;

        // Maps partitions to their respective splits. A given partition may be split
        // multiple times in a hierarchical fashion (split-join). The first split
        // in the list corresponds to the outer-most split and the last split
        // is the inner-most split. Thus, if a given partition performs a join,
        // the jointed split is the last/inner-most split in parts2splits.
        std::map<IntraPartitionDataflow*, std::list<partSplit*> > parts2splits;

        // Maps analysis partitions to their respective current execution states
        // (these are only upto-date for analyses that are currently stopped)
        std::map<IntraPartitionDataflow*, IntraPartitionDataflowCheckpoint*> parts2chkpts;

        // Sample interprocedural analysis object that we'll use as a factory to create more such objects
        IntraPartitionDataflow* intraFactory;

        public:
        // Creates a PartitionedAnalysis, starting the analysis with the given
        // master analysis partition and creating an initial split that only contains the master.
        PartitionedAnalysis(IntraPartitionDataflow* intraFactory);

        // Create the initial partition state for analyzing some function
        void initMaster();

        // Returns a reference to the master dataflow analysis. At the end of the partitioned analysis,
        // it is this object that owns all the dataflow state generated by the overall analysis.
        IntraPartitionDataflow* getMasterDFAnalysis();

        // Activates the given partition, returning true if it was previously inactive and false otherwise.
        bool activatePart(IntraPartitionDataflow* part);

        // Splits the given dataflow analysis partition into several partitions, one for each given checkpoint
        // The partition origA will be assigned the last checkpoint in partitionChkpts.
        // If newSplit==true, this split operation creates a new split within origA's current split and place
        //    the newly-generated partitions into this split.
        // If newSplit==false, the newly-generated partitions will be added to origA's current split.
        // If newPartActive==true, the newly-generated partitions will be made initially active. If not,
        //    they will start out in joined status.
        // Returns the set of newly-created partitions.
        std::set<IntraPartitionDataflow*> split(IntraPartitionDataflow* origA, std::vector<IntraPartitionDataflowCheckpoint*> partitionChkpts,
                                           const Function& func, NodeState* fState, bool newSplit, bool newPartActive);

        // Joins all the analysis partitions in a given split into a single partition, unioning
        // their respective dataflow information
        void join(IntraPartitionDataflow* joinA, IntraPartitionDataflowCheckpoint* chkpt,
                  const Function& func, NodeState* fState);

        // Called by the base PartitionedAnalysis class when all partitions in a given split have decided
        //    to join to decide whether they should be joined or all released. It may also do some
        //    processing of their state prior to the release or join.
        // Returns the set of partitions that will remain in joined status after this join. If all partitions in the split
        //    set are on this list, they are all joined(all but one will be deleted). Any remaining partitions will be released.
        virtual std::set<IntraPartitionDataflow*> preJoin(partSplit* s, const Function& func, NodeState* fState,
                                                     const std::map<IntraPartitionDataflow*,
                                                     IntraPartitionDataflowCheckpoint*>& parts2chkpts)=0;

        // Called by the base PartitionedAnalysis class when all partitions in a given split have
        //    finished their respective executions.
        virtual void postFinish(partSplit* s,
                                const std::map<IntraPartitionDataflow*, IntraPartitionDataflowCheckpoint*>& parts2chkpts)=0;

        // runs the intra-procedural analysis on the given function, returns true if
        // the function's NodeState gets modified as a result and false otherwise
        // state - the function's NodeState
        bool runAnalysis(const Function& func, NodeState* state);
};

// Given a source analysis, splits the dataflow states of all the CFG nodes in
// a given function so that the target analysis gets copies of the source analysis'
// state.
class partitionDFAnalysisState: virtual public UnstructuredPassIntraAnalysis
{
        Analysis* srcAnalysis;
        Analysis* tgtAnalysis;

        public:
        partitionDFAnalysisState(Analysis* srcAnalysis, Analysis* tgtAnalysis)
        {
                this->srcAnalysis = srcAnalysis;
                this->tgtAnalysis = tgtAnalysis;
        }

        void visit(const Function& func, const DataflowNode& n, NodeState& state)
        {
                state.cloneAnalysisState(srcAnalysis, tgtAnalysis);
        }
};

// Given a set of analyses, one of which is designated as a master, unions together the
// dataflow states associated on each CFG node with each of these analyses.
// The results are associated on each CFG node with the master analysis.
class unionDFAnalysisStatePartitions: virtual public UnstructuredPassIntraAnalysis
{
        std::set<Analysis*> unionSet;
        Analysis* master;

        public:
        unionDFAnalysisStatePartitions(
                std::set<Analysis*>& unionSet, Analysis* master)
        {
                for(std::set<Analysis*>::iterator it = unionSet.begin(); it!=unionSet.end(); it++)
                { this->unionSet.insert(*it); }
                //this->unionSet = unionSet;
                this->master = master;
        }

        void visit(const Function& func, const DataflowNode& n, NodeState& state);
};

// Deletes all the state associated with the given analyses
class deleteDFAnalysisState: virtual public UnstructuredPassIntraAnalysis
{
        std::set<IntraPartitionDataflow*> tgtA;

        public:
        deleteDFAnalysisState(std::set<IntraPartitionDataflow*>& tgtA)
        {
                this->tgtA = tgtA;
        }

        void visit(const Function& func, const DataflowNode& n, NodeState& state)
        {
                for(std::set<IntraPartitionDataflow*>::iterator it = tgtA.begin(); it!=tgtA.end(); it++)
                        state.deleteState((Analysis*)*it);
        }
};


class IntraPartitionDataflow : virtual public IntraProceduralDataflow
{
        protected:
        PartitionedAnalysis* parent;

        public:
        // The logic expression that describes the invariant that holds for this partition
        /*LogicalCond*/printable* partitionCond;

        IntraPartitionDataflow(const IntraPartitionDataflow& that)
        {
                parent = that.parent;
                partitionCond = that.partitionCond;
        }

        IntraPartitionDataflow(PartitionedAnalysis* parent)
        {
                this->parent = parent;
                partitionCond = NULL;
        }

        ~IntraPartitionDataflow()
        {
                delete partitionCond;
        }

/*      IntraPartitionDataflow()
        {
                parent = NULL;
        }

        void setParent(PartitionedAnalysis* parent)
        {
                this->parent = parent;
        }*/

        PartitionedAnalysis* getParent() const
        {
                return parent;
        }

        // A dummy analysis that is associated with facts connected with the
        // IntraPartitionDataflow-specific logic rather than the logic of a class that
        // derives from IntraPartitionDataflow.
        // Analysis* dummy;

        // Creates a new instance of the derived object that is a copy of the original instance.
        // This instance will be used to instantiate a new partition of the analysis.
        virtual IntraPartitionDataflow* copy()=0;

        virtual bool runAnalysis(const Function& func, NodeState* fState, bool& splitPart,
                                      bool &joinPart, IntraPartitionDataflowCheckpoint*& outChkpt)=0;

        // Resumes the execution of runAnalysis from the given checkpoint
        // splitPart - set by the call to indicate that it exited because it was split
        // joinPart - set by the call to indicate that it exited because it wishes to join the partitions that it split from
        // outChkpt - set by the call to be the checkpoint that representing the state of this analysis at the time of the exit
        //            set to NULL in the case of a normal exit or a split exit
        virtual bool runAnalysisResume(const Function& func, NodeState* fState,
                               IntraPartitionDataflowCheckpoint* chkpt, bool& splitPart,
                               bool &joinPart, IntraPartitionDataflowCheckpoint*& outChkpt)=0;

        // Called when a partition is created to allow a specific analysis to initialize
        // its dataflow information from the partition condition
        virtual void initDFfromPartCond(const Function& func, const DataflowNode& n, NodeState& state,
                                        const std::vector<Lattice*>& dfInfo, const std::vector<NodeFact*>& facts,
                                        /*LogicalCond*/printable* partitionCond) {}
};

class IntraPartitionDataflowCheckpoint
{
        public:
        // A checkpoint of the dataflow state associated with the given state of the dataflow analysis
        dataflow::checkpoint dfChkpt;
        // Set of nodes that this analysis has blocked progress on until the next join point
        std::set<DataflowNode>    joinNodes;
        // The DataflowNode that that analysis was processing when the checkpoint was taken
        DataflowNode*        curNode;
        // The logical condition that is an invariant of all the states of the dataflow analysis
        /*LogicalCond*/printable*         partitionCond;
        // Given that the current node in the dataflow analysis has one or more successors, the index of
        // the given node's successor
        int                  partitionIndex;

        // the arguments to runAnalysis() used as part of the dataflow pass
        const Function& func;
        NodeState* fState;

        IntraPartitionDataflowCheckpoint(IntraPartitionDataflowCheckpoint &that):
                dfChkpt(that.dfChkpt), func(that.func)
        {
                this->joinNodes      = that.joinNodes;
                if(that.curNode)
                        this->curNode     = new DataflowNode(*(that.curNode));
                else
                        this->curNode     = NULL;

                this->partitionCond  = that.partitionCond;
                this->partitionIndex = that.partitionIndex;
                this->fState         = that.fState;
        }

        IntraPartitionDataflowCheckpoint(dataflow::checkpoint& dfChkpt, const std::set<DataflowNode>& joinNodes,
                                         const DataflowNode* curNode,
                                         /*LogicalCond*/printable* partitionCond, int partitionIndex,
                                         const Function& func, NodeState* fState) :
                dfChkpt(dfChkpt), func(func)
        {
                this->joinNodes      = joinNodes;
                if(curNode)
                        this->curNode     = new DataflowNode(*curNode);
                else
                        this->curNode     = NULL;

                this->partitionCond  = partitionCond;
                this->partitionIndex = partitionIndex;
                this->fState         = fState;
        }

        ~IntraPartitionDataflowCheckpoint()
        {
                //delete partitionCond;
                if(curNode)
                        delete curNode;
        }

        std::string str(std::string indent="")
        {
          std::ostringstream outs;
                outs << indent << "[IntraPartitionDataflowCheckpoint : \n"; //fflush(stdout);
                outs << indent << "    dfChkpt = \n"<<dfChkpt.str(indent+"    ")<<"\n";
                if(curNode)
                        outs << indent << "    curNode = <"<<curNode->getNode()->class_name()<<" | "<<curNode->getNode()->unparseToString()<<" | "<< curNode->getIndex() << ">\n";
                else
                        outs << indent << "    curNode = NULL\n";

                if(joinNodes.size()==0)
        outs << indent << "    joinNodes = None\n";
      else
      {
        outs << indent << "    joinNodes = \n";
                        for(std::set<DataflowNode>::iterator it=joinNodes.begin(); it!=joinNodes.end(); it++)
                        { outs << indent << "        <"<<(*it).getNode()->class_name()<<" | "<<(*it).getNode()->unparseToString()<<">\n"; }
                }
                if(partitionCond)
                        outs << indent << "    partitionCond = \n"<<partitionCond->str(indent+"        ")<<"\n";

                if(partitionIndex>=0)
                        outs << indent << "    partitionIndex = descendant "<<partitionIndex<<"]";
                else
                        outs << indent << "    partitionIndex = all descendants ("<<partitionIndex<<")]";
                return outs.str();
        }
};

class IntraPartitionFWDataflow  : public virtual IntraPartitionDataflow
{
        protected:
        //std::vector<<Lattice*> initState;

        //std::map <DataflowNode, Lattice*> nodeState;
        //std::map<DataflowNode, std::list<Lattice*> > nodeState;

        public:
        IntraPartitionFWDataflow(PartitionedAnalysis* parent): IntraPartitionDataflow(parent)
        { }

        IntraPartitionFWDataflow(const IntraPartitionFWDataflow& that):
                        IntraPartitionDataflow((const IntraPartitionDataflow&)that)
        {
                //this->initState = that.initState;
        }

        /*IntraPartitionFWDataflow(): IntraPartitionDataflow()
        { }*/

        // the transfer function that is applied to every node
        // n - the dataflow node that is being processed
        // state - the NodeState object that describes the state of the node, as established by earlier
        //         analysis passes
        // dfInfo - the Lattices that this transfer function operates on. The function takes these lattices
        //          as input and overwrites them with the result of the transfer.
        // splitAnalysis - set by callee to
        //    - noSplit if the analysis does not want a split
        //    - splitNew if the analysis wants to perform a split and place the newly-generated partitions into
        //      a fresh split set that is nested inside this partition's current split
        //    - splitParent if the analysis wants to perform a split and place the newly-generated partitions
        //      into this partition's current split (i.e. on the same split level as the current partition)
        typedef enum {noSplit, splitNew, splitParent} splitType;
        // splitConditions - if splitAnalysis==splitNew or ==splitParent, the analysis sets this vector to the conditions for all the
        //                   descendant CFG nodes in the split
        /* // joinAnalysis - set to true if the analysis wants to perform a join */
        // joinNode - set to true if progress along the given dataflow node needs to be blocked until the next join point.
        //            If all paths of dataflow progress are blocked in this analysis, this is the same as the analysis
        //            requesting to be joined.
        // Returns true if any of the input lattices changed as a result of the transfer function and
        //    false otherwise.
        virtual bool transfer(const Function& func, const DataflowNode& n, NodeState& state, const std::vector<Lattice*>& dfInfo,
                              splitType& splitAnalysis, std::vector</*LogicalCond*/printable*>& splitConditions, /*bool& joinAnalysis, */bool& joinNode)=0;

        // Runs the intra-procedural analysis on the given function. Returns true if
        // the function's NodeState gets modified as a result and false otherwise.
        // state - the function's NodeState
        bool runAnalysis(const Function& func, NodeState* fState, bool analyzeDueToCallers, std::set<Function> calleesUpdated);

        // Runs the intra-procedural analysis on the given function.
        // Returns true if the function's NodeState gets modified as a result and false otherwise.
        // state - the function's NodeState
        bool runAnalysis(const Function& func, NodeState* fState,
                         bool& splitPart, bool &joinPart, IntraPartitionDataflowCheckpoint*& outChkpt);

        // Resumes the execution of runAnalysis from the given checkpoint
        bool runAnalysisResume(const Function& func, NodeState* fState,
                               IntraPartitionDataflowCheckpoint* chkpt, bool& splitPart,
                               bool &joinPart, IntraPartitionDataflowCheckpoint*& outChkpt);

        typedef enum {retFalse, cont, normal} partitionTranferRet;

        partitionTranferRet partitionTranfer(
                                   const Function& func, NodeState* fState, const DataflowNode& n, NodeState* state, VirtualCFG::dataflow& dfIt,
                                   const std::vector<Lattice*>& dfInfoBelow, bool& splitPart, std::set<DataflowNode>& joinNodes,
                                   IntraPartitionDataflowCheckpoint*& outChkpt);

        // propagates the forward dataflow info from the current node's NodeState (curNodeState) to the next node's
        // NodeState (nextNodeState)
        bool propagateFWStateToNextNode(
             const std::vector<Lattice*>& curNodeState, DataflowNode curDFNode, int nodeIndex,
             const std::vector<Lattice*>& nextNodeState, DataflowNode nextDFNode);
};

#endif
#endif