Program Listing for File VariableRenaming.h#
↰ Return to documentation for file (src/midend/programAnalysis/variableRenaming/VariableRenaming.h)
//Author: Justin Frye
#ifndef SSAANALYSIS_H
#define SSAANALYSIS_H
#include <string>
#include <iostream>
#include <map>
#include <vector>
#include <algorithm>
#include <ostream>
#include <fstream>
#include <sstream>
#include "filteredCFG.h"
#include <unordered_map>
class VarUniqueName : public AstAttribute
{
private:
std::vector<SgInitializedName*> key;
bool usesThis; // this pointer??
public:
VarUniqueName() : key(), usesThis(false)
{
}
VarUniqueName(SgInitializedName* thisNode):usesThis(false)
{
key.push_back(thisNode);
}
VarUniqueName(const std::vector<SgInitializedName*>& prefix, SgInitializedName* thisNode):usesThis(false)
{
key.assign(prefix.begin(),prefix.end());
key.push_back(thisNode);
}
VarUniqueName(const VarUniqueName& other): AstAttribute(other), usesThis(false)
{
key.assign(other.key.begin(), other.key.end());
}
VarUniqueName* copy() const
{
VarUniqueName* newName = new VarUniqueName(*this);
return newName;
}
std::vector<SgInitializedName*>& getKey() { return key; }
void setKey(const std::vector<SgInitializedName*>& newKey) { key.assign(newKey.begin(),newKey.end()); }
bool getUsesThis() { return usesThis; }
void setUsesThis(bool uses) { usesThis = uses; }
std::string getNameString()
{
std::string name = "";
std::vector<SgInitializedName*>::iterator iter;
if(usesThis)
name += "this->";
for(iter = key.begin(); iter != key.end(); ++iter)
{
if(iter != key.begin())
{
name += ":"; // why ":" instead of "." ??
}
name += (*iter)->get_name().getString();
}
return name;
}
};
struct IsDefUseFilter
{
bool operator() (CFGNode cfgn) const
{
SgNode *node = cfgn.getNode();
//If it is the last node in a function call, keep it
if (isSgFunctionCallExp(node) && cfgn == node->cfgForEnd())
return true;
//The begin edges of basic blocks are not considered interesting, but we would like to keep them
//This is so we can propagate reachable defs to the top of a basic block
if (isSgBasicBlock(node) && cfgn == node->cfgForBeginning())
return true;
if (isSgExprStatement(node))
return (cfgn == node->cfgForBeginning());
if (isSgCommaOpExp(node))
return (cfgn == node->cfgForBeginning());
//Remove all non-interesting nodes
//putting this if-statement here may shadow the rest statements, by Liao
//TODO this may be a bug, it should be moved to the end
if (!cfgn.isInteresting())
return false;
//Remove all non-end nodes for initNames
if (isSgInitializedName(node) && cfgn != node->cfgForEnd())
return false;
//Remove non-beginning nodes for try statements
if (isSgTryStmt(node) && cfgn != node->cfgForBeginning())
return false;
//Use the last node of binary operators
if (isSgAndOp(node) || isSgOrOp(node))
{
if (cfgn != node->cfgForEnd())
return false;
}
//We only want the middle appearance of the teritatry operator - after its conditional expression
//and before the true and false bodies. This makes it behave as an if statement for data flow
//purposes
if (isSgConditionalExp(node))
{
return cfgn.getIndex() == 1;
}
return true;
}
};
template <typename T>
struct VectorHash {
std::size_t operator()(const std::vector<T>& vec) const {
std::hash<T> hasher;
std::size_t seed = 0;
for (const T& elem : vec) {
seed ^= hasher(elem) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
}
return seed;
}
};
class VariableRenaming
{
private:
SgProject* project;
bool DEBUG_MODE;
bool DEBUG_MODE_EXTRA;
public:
typedef std::vector<SgNode*> NodeVec;
typedef std::vector<SgInitializedName*> VarName;
typedef std::map<VarName, NodeVec> TableEntry;
typedef std::unordered_map<SgNode*, TableEntry> DefUseTable;
typedef std::unordered_map<VarName, SgNode*, VectorHash<SgInitializedName*>> FirstDefTable;
typedef std::vector<SgInitializedName*> InitNameVec;
typedef FilteredCFGNode<IsDefUseFilter> cfgNode;
typedef FilteredCFGEdge<IsDefUseFilter> cfgEdge;
typedef std::vector<cfgNode> cfgNodeVec;
typedef std::vector<cfgEdge> cfgEdgeVec;
typedef std::map<SgNode*, int> NodeNumRenameEntry;
typedef std::unordered_map<VarName, NodeNumRenameEntry, VectorHash<SgInitializedName*>> NodeNumRenameTable;
typedef std::map<int, SgNode*> NumNodeRenameEntry;
typedef std::unordered_map<VarName, NumNodeRenameEntry, VectorHash<SgInitializedName*>> NumNodeRenameTable;
private:
//Private member variables
DefUseTable originalDefTable;
DefUseTable expandedDefTable;
DefUseTable defTable;
DefUseTable useTable;
FirstDefTable firstDefList;
NodeNumRenameTable nodeRenameTable;
NumNodeRenameTable numRenameTable;
public:
VariableRenaming(SgProject* proj): project(proj), DEBUG_MODE(SgProject::get_verbose() > 0), DEBUG_MODE_EXTRA(SgProject::get_verbose() > 1){}
~VariableRenaming(){}
void run();
bool getDebug() const { return DEBUG_MODE; }
bool getDebugExtra() const { return DEBUG_MODE_EXTRA; }
private:
void runDefUse(SgFunctionDefinition* func);
bool defUse(cfgNode node, bool *memberRefInserted, NodeVec &changedNodes);
int addRenameNumberForNode(const VarName& var, SgNode* node);
bool isBuiltinVar(const VarName& var);
bool mergeDefs(cfgNode curNode, bool *memberRefInserted, NodeVec &changedNodes);
bool resolveUses(cfgNode curNode, bool *memberRefInserted, NodeVec &changedNodes);
void aggregatePreviousDefs(cfgNode curNode, TableEntry& results);
bool expandMemberDefinitions(cfgNode curNode);
bool insertExpandedDefsForUse(cfgNode curNode, VarName name, NodeVec &changedNodes);
bool expandMemberUses(cfgNode curNode);
void insertDefsForExternalVariables(SgFunctionDeclaration* function);
std::set<VarName> getVarsUsedInSubtree(SgNode* root);
void printToDOT(SgSourceFile* file, std::ofstream &outFile);
void printToFilteredDOT(SgSourceFile* file, std::ofstream &outFile);
void printUses(const TableEntry& table);
void printDefs(const TableEntry& table);
public:
//External static helper functions/variables
static std::string varKeyTag;
static SgInitializedName* thisDecl;
static VarName emptyName;
static NumNodeRenameTable emptyRenameTable;
static NumNodeRenameEntry emptyRenameEntry;
/*
* Printing functions.
*/
void toDOT(const std::string fileName);
void toFilteredDOT(const std::string fileName);
static std::string keyToString(const VarName& vec);
void printDefs(SgNode* node);
void printOriginalDefs(SgNode* node);
void printOriginalDefTable();
void printUses(SgNode* node);
void printRenameTable();
void printRenameTable(const VarName& var);
static void printRenameTable(const NodeNumRenameTable& table);
static void printRenameTable(const NumNodeRenameTable& table);
static void printRenameEntry(const NodeNumRenameEntry& entry);
static void printRenameEntry(const NumNodeRenameEntry& entry);
/*
* Def/Use Table Access Functions
*/
DefUseTable& getDefTable(){ return originalDefTable; }
const DefUseTable& getDefTable() const { return originalDefTable; }
DefUseTable& getPropDefTable(){ return defTable; }
const DefUseTable& getPropDefTable() const { return defTable; }
DefUseTable& getUseTable(){ return useTable; }
const DefUseTable& getUseTable() const { return useTable; }
/*
* Rename Table Access Functions
*/
int getRenameNumberForNode(const VarName& var, SgNode* node) const;
SgNode* getNodeForRenameNumber(const VarName& var, int num) const;
int getMaxRenameNumberForName(const VarName& var) const;
/*
* Variable Renaming Access Functions
*/
NodeVec getAllUsesForDef(const VarName& var, int num);
template<typename T> inline std::vector<T*> getAllUsesForDef(const VarName& var, int num)
{
NodeVec vec = getAllUsesForDef(var, num);
std::vector<T*> res;
T* temp = NULL;
for(NodeVec::value_type& val: vec)
{
temp = dynamic_cast<T*>(val);
if(temp != NULL)
{
//Push back if it casts correctly.
res.push_back(temp);
}
}
return res;
}
NumNodeRenameTable getReachingDefsAtNode(SgNode* node);
NumNodeRenameEntry getReachingDefsAtNodeForName(SgNode* node, const VarName& var);
NumNodeRenameTable getReachingDefsAtScopeEnd(SgScopeStatement* scope);
NumNodeRenameTable getReachingDefsAtFunctionEnd(SgFunctionDefinition* node);
NumNodeRenameEntry getReachingDefsAtFunctionEndForName(SgFunctionDefinition* node, const VarName& var);
NumNodeRenameTable getReachingDefsAtStatementStart(SgStatement* statement);
NumNodeRenameTable getReachingDefsAtFunctionStart(SgFunctionDefinition* node);
NumNodeRenameEntry getReachingDefsAtFunctionStartForName(SgFunctionDefinition* node, const VarName& var);
NumNodeRenameTable getUsesAtNode(SgNode* node);
NumNodeRenameTable getOriginalUsesAtNode(SgNode* node);
NumNodeRenameEntry getUsesAtNodeForName(SgNode* node, const VarName& var);
NumNodeRenameTable getDefsAtNode(SgNode* node);
NumNodeRenameEntry getDefsAtNodeForName(SgNode* node, const VarName& var);
NumNodeRenameTable getOriginalDefsAtNode(SgNode* node);
NumNodeRenameEntry getOriginalDefsAtNodeForName(SgNode* node, const VarName& var);
NumNodeRenameTable getExpandedDefsAtNode(SgNode* node);
NumNodeRenameEntry getExpandedDefsAtNodeForName(SgNode* node, const VarName& var);
NumNodeRenameTable getDefsForSubtree(SgNode* node);
NumNodeRenameTable getOriginalDefsForSubtree(SgNode* node);
/*
* Static Utility Functions
*/
static bool isPrefixOfName(VarName name, VarName prefix);
static VarUniqueName* getUniqueName(SgNode* node);
static VarName getVarName(SgNode* node);
static bool isFromLibrary(SgFunctionDeclaration* node);
static SgExpression* buildVariableReference(const VarName& var, SgScopeStatement* scope = NULL);
private:
class VarRefSynthAttr
{
private:
std::vector<SgNode*> refs;
public:
VarRefSynthAttr():refs(){}
VarRefSynthAttr(SgNode* thisNode)
{
refs.push_back(thisNode);
}
VarRefSynthAttr(const std::vector<SgNode*>& subtree, SgNode* thisNode)
{
refs.assign(subtree.begin(), subtree.end());
refs.push_back(thisNode);
}
VarRefSynthAttr(const std::vector<SgNode*>& subtree)
{
refs.assign(subtree.begin(), subtree.end());
}
const std::vector<SgNode*>& getRefs() { return refs; }
void setRefs(const std::vector<SgNode*>& newRefs) { refs.assign(newRefs.begin(), newRefs.end()); }
};
class UniqueNameTraversal : public AstBottomUpProcessing<VariableRenaming::VarRefSynthAttr>
{
VariableRenaming* varRename;
std::vector<SgInitializedName*> allInitNames;
SgInitializedName* resolveTemporaryInitNames(SgInitializedName* name);
public:
UniqueNameTraversal(VariableRenaming* varRenaming, const std::vector<SgInitializedName*>& allNames):
varRename(varRenaming), allInitNames(allNames)
{
}
virtual VariableRenaming::VarRefSynthAttr evaluateSynthesizedAttribute(SgNode* node, SynthesizedAttributesList attrs);
};
class ChildUses
{
private:
SgVarRefExp* currentVar;
std::vector<SgNode*> uses;
public:
ChildUses() : currentVar(NULL)
{ }
ChildUses(SgNode* useNode, SgVarRefExp* var)
{
uses.push_back(useNode);
currentVar = var;
}
ChildUses(const std::vector<SgNode*>& useTree, SgVarRefExp* var = NULL)
{
if (useTree.size() > 0)
uses.assign(useTree.begin(), useTree.end());
currentVar = var;
}
std::vector<SgNode*>& getUses()
{
return uses;
}
void setUses(const std::vector<SgNode*>& newUses)
{
uses.assign(newUses.begin(), newUses.end());
}
SgVarRefExp* getCurrentVar() const
{
return currentVar;
}
};
class DefsAndUsesTraversal : public AstBottomUpProcessing<ChildUses>
{
VariableRenaming* ssa;
public:
DefsAndUsesTraversal(VariableRenaming* ssa) : ssa(ssa) { }
virtual ChildUses evaluateSynthesizedAttribute(SgNode* node, SynthesizedAttributesList attrs);
private:
void addUsesToNode(SgNode* node, std::vector<SgNode*> uses);
void addDefForVarAtNode(SgVarRefExp* currentVar, SgNode* defNode);
};
};
#endif /* SSAANALYSIS_H */