moved
This commit is contained in:
1229
Sapfor/_src/CFGraph/CFGraph.cpp
Normal file
1229
Sapfor/_src/CFGraph/CFGraph.cpp
Normal file
File diff suppressed because it is too large
Load Diff
149
Sapfor/_src/CFGraph/CFGraph.h
Normal file
149
Sapfor/_src/CFGraph/CFGraph.h
Normal file
@@ -0,0 +1,149 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
#include "IR.h"
|
||||
|
||||
namespace SAPFOR
|
||||
{
|
||||
enum CFG_VAL : int { KILL_ALL = -1, UNINIT = -2 };
|
||||
|
||||
class IR_Block;
|
||||
class Argument;
|
||||
class Instruction;
|
||||
|
||||
class BasicBlock
|
||||
{
|
||||
static int lastNumBlock;
|
||||
private:
|
||||
int num;
|
||||
std::vector<IR_Block*> instructions;
|
||||
|
||||
std::vector<BasicBlock*> next;
|
||||
std::vector<BasicBlock*> prev;
|
||||
|
||||
//reaching definition
|
||||
std::map<SAPFOR::Argument*, std::set<int>> RD_in, RD_out;
|
||||
|
||||
//live variables [arg -> blocks with usages]
|
||||
std::map<SAPFOR::Argument*, std::vector<SAPFOR::BasicBlock*>> live_in, live_out, live_inout;
|
||||
|
||||
bool addLive(const std::map<SAPFOR::Argument*, std::vector<SAPFOR::BasicBlock*>>& to_add, bool in);
|
||||
std::map<SAPFOR::Argument*, std::vector<SAPFOR::BasicBlock*>> getLive(bool in) const;
|
||||
bool removeLive(SAPFOR::Argument* to_remove, bool in);
|
||||
public:
|
||||
BasicBlock() { num = lastNumBlock++; }
|
||||
BasicBlock(IR_Block* item);
|
||||
BasicBlock(const BasicBlock& copyFrom);
|
||||
|
||||
void addInstruction(IR_Block* item);
|
||||
void addPrev(BasicBlock* prev_) { prev.push_back(prev_); }
|
||||
void addNext(BasicBlock* next_) { next.push_back(next_); }
|
||||
|
||||
int removePrev(BasicBlock* removed);
|
||||
int removeNext(BasicBlock* removed);
|
||||
|
||||
void replacePrevNext(const std::map<BasicBlock*, BasicBlock*>& oldToNew)
|
||||
{
|
||||
for (int z = 0; z < next.size(); ++z)
|
||||
{
|
||||
auto it = oldToNew.find(next[z]);
|
||||
if (it == oldToNew.end())
|
||||
printInternalError(convertFileName(__FILE__).c_str(), __LINE__);
|
||||
next[z] = it->second;
|
||||
}
|
||||
|
||||
for (int z = 0; z < prev.size(); ++z)
|
||||
{
|
||||
auto it = oldToNew.find(prev[z]);
|
||||
if (it == oldToNew.end())
|
||||
printInternalError(convertFileName(__FILE__).c_str(), __LINE__);
|
||||
prev[z] = it->second;
|
||||
}
|
||||
}
|
||||
|
||||
int getNumber() const { return num; }
|
||||
const std::vector<IR_Block*>& getInstructions() const { return instructions; }
|
||||
const std::vector<BasicBlock*>& getNext() const { return next; }
|
||||
const std::vector<BasicBlock*>& getPrev() const { return prev; }
|
||||
|
||||
/*
|
||||
* FOR LIVE ANALYSIS
|
||||
*/
|
||||
bool addLiveIn(const std::map<SAPFOR::Argument*, std::vector<SAPFOR::BasicBlock*>>& to_add) { return addLive(to_add, true); };
|
||||
bool addLiveOut(const std::map<SAPFOR::Argument*, std::vector<SAPFOR::BasicBlock*>>& to_add) { return addLive(to_add, false); };
|
||||
|
||||
bool removeLiveIn(SAPFOR::Argument* to_remove) { return removeLive(to_remove, true); };
|
||||
bool removeLiveOut(SAPFOR::Argument* to_remove) { return removeLive(to_remove, false); };
|
||||
|
||||
std::map<SAPFOR::Argument*, std::vector<SAPFOR::BasicBlock*>> getLiveIn() const { return getLive(true); };
|
||||
std::map<SAPFOR::Argument*, std::vector<SAPFOR::BasicBlock*>> getLiveOut() const { return getLive(false); };
|
||||
void compressLives();
|
||||
|
||||
/*
|
||||
* FOR REACHING DEFINITIONS
|
||||
*/
|
||||
void setRD_In(const std::map<Argument*, std::set<int>>& inSet) { RD_in = inSet; }
|
||||
void setRD_Out(const std::map<Argument*, std::set<int>>& outSet) { RD_out = outSet; }
|
||||
const std::map<Argument*, std::set<int>>& getRD_In() const { return RD_in; }
|
||||
const std::map<Argument*, std::set<int>>& getRD_Out() const { return RD_out; }
|
||||
std::map<Argument*, std::set<int>>& getModRD_In() { return RD_in; }
|
||||
std::map<Argument*, std::set<int>>& getModRD_Out() { return RD_out; }
|
||||
|
||||
~BasicBlock();
|
||||
};
|
||||
|
||||
struct CFG_Settings
|
||||
{
|
||||
bool atLeastOneIterInLoop = false;
|
||||
bool withRD = true;
|
||||
bool withRegisters = false;
|
||||
bool withSPF = false;
|
||||
bool withDVM = false;
|
||||
bool withCallsInBlocks = false; // separate each F_CALL to own BasicBlock
|
||||
bool withCallFrom = true;
|
||||
|
||||
explicit CFG_Settings(int) { }
|
||||
|
||||
explicit CFG_Settings(bool atLeastOneIterInLoop = false, bool withRD = true, bool withRegisters = false,
|
||||
bool withDVM = false, bool withSPF = false, bool withCallsInBlocks = false, bool withCallFrom = true) :
|
||||
atLeastOneIterInLoop(atLeastOneIterInLoop), withRD(withRD), withRegisters(withRegisters), withDVM(withDVM), withSPF(withSPF),
|
||||
withCallsInBlocks(withCallsInBlocks), withCallFrom(withCallFrom)
|
||||
{ }
|
||||
};
|
||||
}
|
||||
|
||||
std::map<FuncInfo*, std::vector<SAPFOR::BasicBlock*>> buildCFG(const std::map<std::string, CommonBlock*>& commonBlocks, const std::map<std::string, std::vector<FuncInfo*>>& allFuncInfo, const SAPFOR::CFG_Settings settings);
|
||||
std::map<FuncInfo*, std::vector<SAPFOR::BasicBlock*>> buildCFGforCurrentFunc(SgStatement* stmt, SAPFOR::CFG_Settings settings, const std::map<std::string, CommonBlock*>& commonBlocks, const std::map<std::string, std::vector<FuncInfo*>>& allFuncInfo);
|
||||
|
||||
std::vector<std::pair<const Variable*, CommonBlock*>> getCommonsByFunction(SgFile* file, SgStatement* function, const std::map<std::string, CommonBlock*>& commonBlocks);
|
||||
std::vector<SAPFOR::IR_Block*> getAllIR(const std::vector<SAPFOR::BasicBlock*>& blocks);
|
||||
void dumpCFG(const std::map<FuncInfo*, std::vector<SAPFOR::BasicBlock*>>& blocks, bool withRD);
|
||||
std::vector<std::set<FuncInfo*>> groupByCallDependencies(const std::map<FuncInfo*, std::set<FuncInfo*>>& callDeps, std::vector<std::set<FuncInfo*>>& scc);
|
||||
|
||||
template<typename T>
|
||||
bool intersectAndAdd(std::set<T>& s1, const std::set<T>& s2);
|
||||
|
||||
void buildGenKillForCFG(const std::vector<SAPFOR::BasicBlock*>& CFG,
|
||||
const std::map<std::string, FuncInfo*>& funcByName,
|
||||
const std::map<FuncInfo*, std::map<SAPFOR::Argument*, std::set<int>>>& outForFunc,
|
||||
std::map<SAPFOR::BasicBlock*, std::map<SAPFOR::Argument*, std::set<int>>>& gen,
|
||||
std::map<SAPFOR::BasicBlock*, std::map<SAPFOR::Argument*, std::set<int>>>& kill,
|
||||
std::map<SAPFOR::Instruction*, std::map<SAPFOR::Argument*, std::set<int>>>* genForIR,
|
||||
std::map<SAPFOR::Instruction*, std::map<SAPFOR::Argument*, std::set<int>>>* killForIR,
|
||||
std::map<SAPFOR::BasicBlock*, std::set<SAPFOR::Argument*>>& notInitedGlobals,
|
||||
const SAPFOR::CFG_Settings settings);
|
||||
|
||||
static inline void deleteCFG(std::map<FuncInfo*, std::vector<SAPFOR::BasicBlock*>>& cfg)
|
||||
{
|
||||
for (auto& byFunc : cfg)
|
||||
{
|
||||
for (auto& block : byFunc.second)
|
||||
delete block;
|
||||
byFunc.second.clear();
|
||||
}
|
||||
cfg.clear();
|
||||
}
|
||||
21
Sapfor/_src/CFGraph/DataFlow/backward_data_flow.h
Normal file
21
Sapfor/_src/CFGraph/DataFlow/backward_data_flow.h
Normal file
@@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
#include "data_flow.h"
|
||||
|
||||
#include <vector>
|
||||
#include <set>
|
||||
#include <algorithm>
|
||||
|
||||
#include "../../Utils/SgUtils.h"
|
||||
#include "../CFGraph.h"
|
||||
#include "../IR.h"
|
||||
|
||||
template <class NodeType>
|
||||
class BackwardDataFlowAnalysis : public DataFlowAnalysis<NodeType>
|
||||
{
|
||||
std::vector<SAPFOR::BasicBlock*> reorderSequence(const std::vector<SAPFOR::BasicBlock*>& blocks,
|
||||
const std::set<SAPFOR::BasicBlock*> back_edge_sources);
|
||||
public:
|
||||
void fit(const std::vector<SAPFOR::BasicBlock*>& blocks);
|
||||
};
|
||||
|
||||
#include "backward_data_flow_impl.h"
|
||||
103
Sapfor/_src/CFGraph/DataFlow/backward_data_flow_impl.h
Normal file
103
Sapfor/_src/CFGraph/DataFlow/backward_data_flow_impl.h
Normal file
@@ -0,0 +1,103 @@
|
||||
#pragma once
|
||||
#include "backward_data_flow.h"
|
||||
|
||||
#include <vector>
|
||||
#include <set>
|
||||
#include <algorithm>
|
||||
|
||||
#include "../../Utils/SgUtils.h"
|
||||
#include "../CFGraph.h"
|
||||
#include "../IR.h"
|
||||
#include "../RD_subst.h"
|
||||
|
||||
/* Note: this file should be included in backward_data_flow.h to provide template definitions */
|
||||
|
||||
// minimizes the number of blocks beween the ends of back edges
|
||||
template <class NodeType>
|
||||
std::vector<SAPFOR::BasicBlock*>
|
||||
BackwardDataFlowAnalysis<NodeType>::reorderSequence(const std::vector<SAPFOR::BasicBlock*>& blocks,
|
||||
const std::set<SAPFOR::BasicBlock*> back_edge_sources)
|
||||
{
|
||||
std::vector<SAPFOR::BasicBlock*> res = { };
|
||||
|
||||
auto blocks_end = blocks.rend();
|
||||
for (auto it = blocks.rbegin(); it < blocks_end; it++)
|
||||
{
|
||||
SAPFOR::BasicBlock* curr = *it;
|
||||
auto res_end = res.end();
|
||||
auto inserter = res.begin();
|
||||
if (back_edge_sources.count(curr) == 0)
|
||||
{
|
||||
auto curr_next_begin = curr->getNext().begin();
|
||||
auto curr_next_end = curr->getNext().end();
|
||||
while (inserter < res_end && std::find(curr_next_begin, curr_next_end, *inserter) == curr_next_end)
|
||||
inserter++;
|
||||
}
|
||||
|
||||
res.insert(inserter, curr);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
template <class NodeType>
|
||||
void BackwardDataFlowAnalysis<NodeType>::fit(const std::vector<SAPFOR::BasicBlock*>& blocks)
|
||||
{
|
||||
std::set<std::pair<SAPFOR::BasicBlock*, SAPFOR::BasicBlock*>> back_edges = {};
|
||||
|
||||
bool returned = false;
|
||||
std::map<SAPFOR::BasicBlock*, std::set<SAPFOR::BasicBlock*>> back_edges_by_src;
|
||||
|
||||
auto blocks_sorted = sortCfgNodes(blocks, &back_edges);
|
||||
|
||||
std::set<SAPFOR::BasicBlock*> back_edge_sources;
|
||||
|
||||
for (auto& edge : back_edges)
|
||||
{
|
||||
back_edges_by_src[edge.first].insert(edge.second);
|
||||
back_edge_sources.insert(edge.first);
|
||||
}
|
||||
|
||||
back_edges.clear();
|
||||
|
||||
blocks_sorted = reorderSequence(blocks_sorted, back_edge_sources);
|
||||
back_edge_sources.clear();
|
||||
|
||||
std::reverse(blocks_sorted.begin(), blocks_sorted.end());
|
||||
|
||||
this->nodes.clear();
|
||||
std::map<SAPFOR::BasicBlock*, NodeType*> node_by_block;
|
||||
|
||||
for (auto block : blocks_sorted)
|
||||
{
|
||||
NodeType* node = this->createNode(block);
|
||||
this->nodes.push_back(node);
|
||||
node_by_block[block] = node;
|
||||
}
|
||||
|
||||
int nodes_size = this->nodes.size();
|
||||
|
||||
for (int i = 0; i < nodes_size; i++)
|
||||
{
|
||||
NodeType* node = this->nodes[i];
|
||||
|
||||
auto back_edges_by_src_it = back_edges_by_src.find(node->getBlock());
|
||||
if (back_edges_by_src_it != back_edges_by_src.end())
|
||||
{
|
||||
// This node is a source for back edge
|
||||
for (auto dest : back_edges_by_src_it->second)
|
||||
{
|
||||
auto node_by_block_it = node_by_block.find(dest);
|
||||
if (node_by_block_it != node_by_block.end())
|
||||
node_by_block_it->second->getRollback().insert(i);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto next : node->getBlock()->getNext())
|
||||
{
|
||||
auto node_by_block_it = node_by_block.find(next);
|
||||
if (node_by_block_it != node_by_block.end())
|
||||
node->getPrevBlocks().insert(node_by_block_it->second);
|
||||
}
|
||||
}
|
||||
}
|
||||
68
Sapfor/_src/CFGraph/DataFlow/data_flow.h
Normal file
68
Sapfor/_src/CFGraph/DataFlow/data_flow.h
Normal file
@@ -0,0 +1,68 @@
|
||||
#pragma once
|
||||
#include<vector>
|
||||
#include<set>
|
||||
|
||||
#include "../../Utils/SgUtils.h"
|
||||
#include "../CFGraph.h"
|
||||
#include "../IR.h"
|
||||
|
||||
enum class DATA_FLOW_UPD_STATUS { NO_CHANGE = 0, PROPAGATED, GENERATED };
|
||||
|
||||
template <class DataType>
|
||||
class DataFlowAnalysisNode {
|
||||
static const int CNT_NOTINIT = 0;
|
||||
|
||||
int in_cnt = CNT_NOTINIT, out_cnt = CNT_NOTINIT;
|
||||
|
||||
std::set<int> rollback;
|
||||
|
||||
std::set<DataFlowAnalysisNode<DataType>*> prev_blocks;
|
||||
|
||||
SAPFOR::BasicBlock* bb;
|
||||
public:
|
||||
DataFlowAnalysisNode();
|
||||
|
||||
void doStep();
|
||||
|
||||
virtual DataType getIn() = 0;
|
||||
virtual DataType getOut() = 0;
|
||||
|
||||
virtual bool addIn(const DataType& data) = 0;
|
||||
virtual bool addOut(const DataType& data) = 0;
|
||||
|
||||
virtual bool updateState() { return false; }
|
||||
virtual DATA_FLOW_UPD_STATUS forwardData(const DataType& data) = 0;
|
||||
|
||||
bool newerThan(const DataFlowAnalysisNode<DataType>* block) const { return out_cnt > block->in_cnt; }
|
||||
|
||||
int getInCnt() { return in_cnt; }
|
||||
int getOutCnt() { return out_cnt; }
|
||||
|
||||
void setInCnt(int cnt) { in_cnt = cnt; }
|
||||
void setOutCnt(int cnt) { out_cnt = cnt; }
|
||||
static int getStartCounter() { return CNT_NOTINIT; }
|
||||
|
||||
std::set<int>& getRollback() { return rollback; }
|
||||
|
||||
std::set<DataFlowAnalysisNode<DataType>*>& getPrevBlocks() { return prev_blocks; }
|
||||
|
||||
SAPFOR::BasicBlock* getBlock() { return bb; }
|
||||
void setBlock(SAPFOR::BasicBlock* b) { bb = b; }
|
||||
};
|
||||
|
||||
template <class NodeType>
|
||||
class DataFlowAnalysis {
|
||||
protected:
|
||||
std::vector<NodeType*> nodes;
|
||||
|
||||
virtual NodeType* createNode(SAPFOR::BasicBlock* block) = 0;
|
||||
public:
|
||||
virtual void fit(const std::vector<SAPFOR::BasicBlock*>& blocks) = 0;
|
||||
void analyze();
|
||||
|
||||
const std::vector<NodeType*>& getNodes() { return nodes; }
|
||||
|
||||
~DataFlowAnalysis();
|
||||
};
|
||||
|
||||
#include "data_flow_impl.h"
|
||||
112
Sapfor/_src/CFGraph/DataFlow/data_flow_impl.h
Normal file
112
Sapfor/_src/CFGraph/DataFlow/data_flow_impl.h
Normal file
@@ -0,0 +1,112 @@
|
||||
#pragma once
|
||||
#include "data_flow.h"
|
||||
|
||||
#include<vector>
|
||||
#include<set>
|
||||
|
||||
#include "../../Utils/SgUtils.h"
|
||||
#include "../CFGraph.h"
|
||||
#include "../IR.h"
|
||||
|
||||
/* Note: this file should be included in data_flow.h to provide template definitions */
|
||||
|
||||
/* definitions for DataFlowAnalysisNode class */
|
||||
|
||||
template <class DataType>
|
||||
const int DataFlowAnalysisNode<DataType>::CNT_NOTINIT;
|
||||
|
||||
template <class DataType>
|
||||
DataFlowAnalysisNode<DataType>::DataFlowAnalysisNode()
|
||||
{
|
||||
getRollback() = {};
|
||||
prev_blocks = {};
|
||||
}
|
||||
|
||||
template <class DataType>
|
||||
void DataFlowAnalysisNode<DataType>::doStep()
|
||||
{
|
||||
int in_max_cnt = CNT_NOTINIT, out_max_cnt = CNT_NOTINIT;
|
||||
|
||||
bool uniq_change = updateState();
|
||||
for (auto next : prev_blocks)
|
||||
{
|
||||
if (in_cnt < next->out_cnt)
|
||||
{
|
||||
if (next->out_cnt > in_max_cnt)
|
||||
in_max_cnt = next->out_cnt;
|
||||
|
||||
const auto& byOut = next->getOut();
|
||||
bool inserted = addIn( byOut);
|
||||
|
||||
if (inserted)
|
||||
{
|
||||
auto status = forwardData(byOut);
|
||||
inserted = status != DATA_FLOW_UPD_STATUS::NO_CHANGE;
|
||||
|
||||
if (inserted && next->out_cnt > out_max_cnt)
|
||||
out_max_cnt = next->out_cnt;
|
||||
|
||||
uniq_change |= status == DATA_FLOW_UPD_STATUS::GENERATED;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uniq_change |= (out_cnt == CNT_NOTINIT);
|
||||
|
||||
if (out_max_cnt != CNT_NOTINIT)
|
||||
out_cnt = out_max_cnt;
|
||||
|
||||
if (in_max_cnt != CNT_NOTINIT)
|
||||
in_cnt = in_max_cnt;
|
||||
|
||||
// TODO: fix counter overflow
|
||||
if (uniq_change)
|
||||
{
|
||||
out_cnt++;
|
||||
in_cnt++;
|
||||
}
|
||||
}
|
||||
|
||||
/* definitions for DataFlowAnalysis class */
|
||||
|
||||
template <class NodeType>
|
||||
void DataFlowAnalysis<NodeType>::analyze()
|
||||
{
|
||||
auto curr = 0;
|
||||
auto stop = nodes.size();
|
||||
|
||||
while (curr != stop)
|
||||
{
|
||||
auto curr_bb = nodes[curr];
|
||||
curr_bb->doStep();
|
||||
|
||||
const auto& jumps = curr_bb->getRollback();
|
||||
if (jumps.size() != 0)
|
||||
{
|
||||
bool jump = false;
|
||||
for (const auto& jump_to : jumps)
|
||||
{
|
||||
if (curr_bb->newerThan(nodes[jump_to]))
|
||||
{
|
||||
jump = true;
|
||||
curr = jump_to;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (jump)
|
||||
continue;
|
||||
}
|
||||
|
||||
curr++;
|
||||
}
|
||||
}
|
||||
|
||||
template <class NodeType>
|
||||
DataFlowAnalysis<NodeType>::~DataFlowAnalysis()
|
||||
{
|
||||
for (NodeType* node : nodes)
|
||||
delete node;
|
||||
|
||||
nodes.clear();
|
||||
}
|
||||
1615
Sapfor/_src/CFGraph/IR.cpp
Normal file
1615
Sapfor/_src/CFGraph/IR.cpp
Normal file
File diff suppressed because it is too large
Load Diff
346
Sapfor/_src/CFGraph/IR.h
Normal file
346
Sapfor/_src/CFGraph/IR.h
Normal file
@@ -0,0 +1,346 @@
|
||||
#pragma once
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
|
||||
#include "CFGraph.h"
|
||||
#include "../Utils/CommonBlock.h"
|
||||
|
||||
namespace SAPFOR
|
||||
{
|
||||
struct CFG_Settings;
|
||||
|
||||
enum class CFG_OP { NONE, ASSIGN, POINTER_ASS, LOAD, STORE, REC_REF_LOAD, REC_REF_STORE, REF, PARAM, IO_PARAM, RANGE, ENTRY, REC_REF,
|
||||
ADD, MULT, DIV, SUBT, UN_ADD, UN_MINUS, POW, CONCAT, CAST,
|
||||
JUMP, JUMP_IF,
|
||||
GE, LE, GT, LT, EQ, NEQV, EQV, EMPTY, OR, AND, NOT,
|
||||
F_CALL, EXIT,
|
||||
DVM_DIR, SPF_DIR };
|
||||
|
||||
enum class CFG_ARG_TYPE { NONE, REG, VAR, ARRAY, CONST, FUNC, LAB, INSTR, CONST_STR, RECORD, CONSTR_REF };
|
||||
enum class CFG_MEM_TYPE { NONE_, COMMON_, SAVE_, LOCAL_, MODULE_, FUNC_RES_, FUNC_PARAM_, FILED_ };
|
||||
|
||||
static std::vector<std::string> CFG_OP_S = { "--", " = ", " => ", "LOAD ", "STORE ", "LOAD_REF ", "STORE_REF ", "REF ", "PARAM ", "IO_PARAM ", "RANGE ", "ENTRY ", "->",
|
||||
" + ", " * ", " / ", " - ", " + ", "-", " ** ", " // ", "CAST ",
|
||||
"GOTO ", "IF_FALSE ",
|
||||
" >= ", " <= ", " > " , " < ", " == ", " != ", " eqv ", "CONTINUE", " || ", " && ", " ! ",
|
||||
"F_CALL ", "EXIT ",
|
||||
" ", " " };
|
||||
|
||||
class Argument
|
||||
{
|
||||
static int lastNumArg;
|
||||
private:
|
||||
int number;
|
||||
|
||||
CFG_ARG_TYPE type;
|
||||
CFG_MEM_TYPE mType;
|
||||
std::string value;
|
||||
public:
|
||||
Argument() : number(lastNumArg++), type(CFG_ARG_TYPE::NONE), value(""), mType(CFG_MEM_TYPE::NONE_) { }
|
||||
Argument(CFG_ARG_TYPE type, CFG_MEM_TYPE mType) : number(lastNumArg++), type(type), mType(mType), value("") { }
|
||||
Argument(CFG_ARG_TYPE type, CFG_MEM_TYPE mType, const std::string& value) : number(lastNumArg++), type(type), mType(mType), value(value) { }
|
||||
Argument(CFG_ARG_TYPE type, const std::string& value) : number(lastNumArg++), type(type), mType(CFG_MEM_TYPE::NONE_), value(value)
|
||||
{
|
||||
if (type != CFG_ARG_TYPE::INSTR && type == CFG_ARG_TYPE::LAB &&
|
||||
type != CFG_ARG_TYPE::NONE && type != CFG_ARG_TYPE::FUNC)
|
||||
{
|
||||
printInternalError(convertFileName(__FILE__).c_str(), __LINE__);
|
||||
}
|
||||
}
|
||||
|
||||
void setType(CFG_ARG_TYPE newType) { type = newType; }
|
||||
CFG_ARG_TYPE getType() const { return type; }
|
||||
|
||||
void setMemType(CFG_MEM_TYPE newType) { mType = newType; }
|
||||
CFG_MEM_TYPE getMemType() const { return mType; }
|
||||
|
||||
bool isMemGlobal() const
|
||||
{
|
||||
if (mType == CFG_MEM_TYPE::COMMON_ ||
|
||||
mType == CFG_MEM_TYPE::MODULE_ ||
|
||||
mType == CFG_MEM_TYPE::SAVE_)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool isParameter() const
|
||||
{
|
||||
if (mType == CFG_MEM_TYPE::FUNC_RES_ ||
|
||||
mType == CFG_MEM_TYPE::FUNC_PARAM_)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void setValue(const std::string& newValue) { value = newValue; }
|
||||
const std::string getValue() const
|
||||
{
|
||||
if (type == CFG_ARG_TYPE::CONST_STR || type == CFG_ARG_TYPE::CONSTR_REF)
|
||||
return "'" + value + "'";
|
||||
else
|
||||
return value;
|
||||
}
|
||||
|
||||
int getNumber() const { return number; }
|
||||
|
||||
std::string getMemTypeStr() const
|
||||
{
|
||||
if (mType == CFG_MEM_TYPE::NONE_)
|
||||
return "none";
|
||||
else if (mType == CFG_MEM_TYPE::COMMON_)
|
||||
return "common";
|
||||
else if (mType == CFG_MEM_TYPE::LOCAL_)
|
||||
return "local";
|
||||
else if (mType == CFG_MEM_TYPE::MODULE_)
|
||||
return "module";
|
||||
else if (mType == CFG_MEM_TYPE::FUNC_RES_)
|
||||
return "func_res";
|
||||
else if (mType == CFG_MEM_TYPE::FUNC_PARAM_)
|
||||
return "func_par";
|
||||
else if (mType == CFG_MEM_TYPE::SAVE_)
|
||||
return "save";
|
||||
else if (mType == CFG_MEM_TYPE::FILED_)
|
||||
return "filed";
|
||||
else
|
||||
return "error";
|
||||
}
|
||||
|
||||
~Argument() { }
|
||||
};
|
||||
|
||||
class Instruction
|
||||
{
|
||||
static int lastNumInstr;
|
||||
private:
|
||||
int number;
|
||||
|
||||
CFG_OP operation;
|
||||
Argument* arg1;
|
||||
Argument* arg2;
|
||||
Argument* result;
|
||||
|
||||
SgStatement* st = NULL;
|
||||
SgExpression* ex = NULL;
|
||||
|
||||
std::string getArgValue(Argument* arg) const
|
||||
{
|
||||
if (arg == NULL)
|
||||
return "";
|
||||
return arg->getValue();
|
||||
}
|
||||
public:
|
||||
|
||||
Instruction() : number(lastNumInstr++), operation(CFG_OP::NONE), arg1(NULL), arg2(NULL), result(NULL) { }
|
||||
Instruction(CFG_OP op, Argument* arg1 = NULL, Argument* arg2 = NULL, Argument* res = NULL, SgStatement* st = NULL, SgExpression* ex = NULL) :
|
||||
number(lastNumInstr++), operation(op), arg1(arg1), arg2(arg2), result(res), st(st), ex(ex) { }
|
||||
|
||||
Instruction(CFG_OP op, SgStatement* st) : number(lastNumInstr++), operation(op), arg1(NULL), arg2(NULL), result(NULL), st(st) { }
|
||||
|
||||
Instruction(CFG_OP op, int num, Argument* arg1 = NULL, Argument* arg2 = NULL, Argument* res = NULL, SgStatement* st = NULL, SgExpression* ex = NULL) :
|
||||
number(num), operation(op), arg1(arg1), arg2(arg2), result(res), st(st), ex(ex) { }
|
||||
|
||||
void setOperation(CFG_OP op) { operation = op; }
|
||||
CFG_OP getOperation() const { return operation; }
|
||||
|
||||
Argument* getArg1() const { return arg1; }
|
||||
Argument* getArg2() const { return arg2; }
|
||||
Argument* getResult() const { return result; }
|
||||
|
||||
void setArg1(Argument* arg) { arg1 = arg; }
|
||||
void setArg2(Argument* arg) { arg2 = arg; }
|
||||
void setResult(Argument* arg) { result = arg; }
|
||||
|
||||
int getNumber() const { return number; }
|
||||
void shiftNumber(int add) { number += add; }
|
||||
|
||||
SgStatement* getOperator() const { return st; }
|
||||
void setOperator(SgStatement* st_) { st = st_; }
|
||||
|
||||
SgExpression* getExpression() const { return ex; }
|
||||
|
||||
int getLine() const { return st ? st->lineNumber() : -1; }
|
||||
|
||||
bool isAccess() const
|
||||
{
|
||||
std::set<CFG_OP> accessOps = { CFG_OP::LOAD , CFG_OP::STORE, CFG_OP::REC_REF_LOAD, CFG_OP::REC_REF_STORE };
|
||||
return accessOps.find(operation) != accessOps.end();
|
||||
}
|
||||
|
||||
bool isArith() const
|
||||
{
|
||||
std::set<CFG_OP> arithOps = { CFG_OP::ADD, CFG_OP::MULT, CFG_OP::DIV, CFG_OP::SUBT, CFG_OP::UN_ADD, CFG_OP::UN_MINUS, CFG_OP::POW, CFG_OP::CONCAT };
|
||||
//CFG_OP::CAST, CFG_OP::GE, CFG_OP::LE, CFG_OP::GT, CFG_OP::LT, CFG_OP::EQ, CFG_OP::NEQV, CFG_OP::EQV, CFG_OP::OR, CFG_OP::AND, CFG_OP::NOT };
|
||||
|
||||
return (arithOps.find(operation) != arithOps.end()) || isIntirinsicCall();
|
||||
}
|
||||
|
||||
bool isIntirinsicCall() const
|
||||
{
|
||||
if (operation == CFG_OP::F_CALL)
|
||||
{
|
||||
if (ex)
|
||||
{
|
||||
if (isIntrinsicFunctionName(ex->symbol()->identifier()))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static int getNextInstrNum() { return lastNumInstr; }
|
||||
static void shiftNextInstrNum(int byNum) { lastNumInstr += byNum; }
|
||||
|
||||
std::string dump()
|
||||
{
|
||||
std::string res = "";
|
||||
|
||||
std::string resultVal = getArgValue(result);
|
||||
std::string arg1Val = getArgValue(arg1);
|
||||
std::string arg2Val = getArgValue(arg2);
|
||||
|
||||
switch (operation)
|
||||
{
|
||||
case CFG_OP::ADD:
|
||||
case CFG_OP::MULT:
|
||||
case CFG_OP::DIV:
|
||||
case CFG_OP::SUBT:
|
||||
case CFG_OP::GE:
|
||||
case CFG_OP::LE:
|
||||
case CFG_OP::GT:
|
||||
case CFG_OP::LT:
|
||||
case CFG_OP::EQ:
|
||||
case CFG_OP::NEQV:
|
||||
case CFG_OP::EQV:
|
||||
case CFG_OP::OR:
|
||||
case CFG_OP::AND:
|
||||
case CFG_OP::POW:
|
||||
case CFG_OP::CONCAT:
|
||||
res = resultVal + " = " + arg1Val + CFG_OP_S[(int)operation] + arg2Val;
|
||||
break;
|
||||
case CFG_OP::NOT:
|
||||
case CFG_OP::UN_MINUS:
|
||||
case CFG_OP::UN_ADD:
|
||||
res = resultVal + " = " + CFG_OP_S[(int)operation] + arg1Val;
|
||||
break;
|
||||
case CFG_OP::POINTER_ASS:
|
||||
res = arg1Val + CFG_OP_S[(int)operation] + resultVal;
|
||||
break;
|
||||
case CFG_OP::ASSIGN:
|
||||
if (arg2)
|
||||
res = resultVal + CFG_OP_S[(int)operation] + arg1Val + " [" + arg2Val + "]";
|
||||
else
|
||||
res = resultVal + CFG_OP_S[(int)operation] + arg1Val;
|
||||
break;
|
||||
case CFG_OP::JUMP:
|
||||
case CFG_OP::ENTRY:
|
||||
res = CFG_OP_S[(int)operation] + arg1Val;
|
||||
break;
|
||||
case CFG_OP::JUMP_IF:
|
||||
res = CFG_OP_S[(int)operation] + arg1Val + " then goto " + arg2Val;
|
||||
break;
|
||||
case CFG_OP::EMPTY:
|
||||
res = CFG_OP_S[(int)operation];
|
||||
break;
|
||||
case CFG_OP::LOAD:
|
||||
case CFG_OP::REC_REF_LOAD:
|
||||
res = CFG_OP_S[(int)operation] + resultVal + " " + arg1Val + (arg2 ? (" " + arg2Val) : "");
|
||||
break;
|
||||
case CFG_OP::REC_REF_STORE:
|
||||
case CFG_OP::STORE:
|
||||
res = CFG_OP_S[(int)operation] + arg1Val + (arg2 ? (" " + arg2Val) : "") + " " + resultVal;
|
||||
break;
|
||||
case CFG_OP::REC_REF:
|
||||
res = "LOAD " + resultVal + " " + arg1Val + CFG_OP_S[(int)operation] + arg2Val;
|
||||
break;
|
||||
case CFG_OP::REF:
|
||||
case CFG_OP::PARAM:
|
||||
case CFG_OP::IO_PARAM:
|
||||
res = CFG_OP_S[(int)operation] + arg1Val;
|
||||
break;
|
||||
case CFG_OP::CAST:
|
||||
res = resultVal + " = " + CFG_OP_S[(int)operation] + arg1Val;
|
||||
break;
|
||||
case CFG_OP::F_CALL:
|
||||
if (result)
|
||||
res = resultVal + " = " + CFG_OP_S[(int)operation] + arg1Val + " " + arg2Val;
|
||||
else
|
||||
res = CFG_OP_S[(int)operation] + arg1Val + " " + arg2Val;
|
||||
break;
|
||||
case CFG_OP::RANGE:
|
||||
res = CFG_OP_S[(int)operation] + "[ ";
|
||||
if (arg1)
|
||||
res += arg1Val;
|
||||
res += " : ";
|
||||
if (arg2)
|
||||
res += arg2Val;
|
||||
res += " : ";
|
||||
if (result)
|
||||
res += resultVal;
|
||||
res += " ]";
|
||||
break;
|
||||
case CFG_OP::DVM_DIR:
|
||||
case CFG_OP::SPF_DIR:
|
||||
res = (st != NULL) ? std::string(st->unparse()) : "NULL";
|
||||
break;
|
||||
default:
|
||||
res = CFG_OP_S[(int)operation];
|
||||
break;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
};
|
||||
|
||||
class IR_Block
|
||||
{
|
||||
private:
|
||||
Instruction* current;
|
||||
Instruction* jumpTo;
|
||||
|
||||
BasicBlock* bblock;
|
||||
bool header;
|
||||
public:
|
||||
IR_Block(Instruction* instr) : current(instr), jumpTo(NULL), bblock(NULL), header(false) { }
|
||||
IR_Block(const IR_Block& copyFrom)
|
||||
{
|
||||
current = new Instruction(*copyFrom.getInstruction());
|
||||
bblock = NULL;
|
||||
//need to replace with actual IR
|
||||
jumpTo = copyFrom.getJump();
|
||||
header = false;
|
||||
}
|
||||
|
||||
Instruction* getInstruction() const { return current; }
|
||||
Instruction* getJump() const { return jumpTo; }
|
||||
BasicBlock* getBasicBlock() const { return bblock; }
|
||||
int getNumber() const { return current->getNumber(); }
|
||||
|
||||
void setJump(Instruction* instr) { jumpTo = instr; }
|
||||
void setBasicBlock(BasicBlock* newBlock) { bblock = newBlock; }
|
||||
|
||||
void setHeader() { header = true; }
|
||||
bool isHeader() const { return header; }
|
||||
|
||||
int getLine() const { return current->getLine(); }
|
||||
|
||||
~IR_Block() { delete current; }
|
||||
};
|
||||
|
||||
class BasicBlock;
|
||||
}
|
||||
|
||||
std::string createName(const std::vector<std::pair<const Variable*, CommonBlock*>>& commonVars, const FuncInfo* func,
|
||||
SgSymbol* s, SgStatement* scope, SAPFOR::CFG_MEM_TYPE& mType);
|
||||
std::string getNameByArg(SAPFOR::Argument* arg);
|
||||
SgSymbol* getSybolByArg(SAPFOR::Argument* arg);
|
||||
SAPFOR::Argument* createArg(const std::string& fullName, const std::string& name, SAPFOR::CFG_MEM_TYPE mType);
|
||||
|
||||
std::vector<SAPFOR::IR_Block*> buildIR(SgStatement* function, const FuncInfo* func, const std::vector<std::pair<const Variable*, CommonBlock*>>& commonVars, const SAPFOR::CFG_Settings settings);
|
||||
SAPFOR::Instruction* getInstructionByNumber(const std::vector<SAPFOR::IR_Block*>& blocks, int num);
|
||||
std::pair<SAPFOR::Instruction*, SAPFOR::BasicBlock*> getInstructionAndBlockByNumber(const std::map<FuncInfo*, std::vector<SAPFOR::BasicBlock*>>& CFGraph, int num);
|
||||
std::pair<SAPFOR::Instruction*, SAPFOR::BasicBlock*> getInstructionAndBlockByStatement(const std::map<FuncInfo*, std::vector<SAPFOR::BasicBlock*>>& CFGraph, SgStatement* stmt);
|
||||
int getParamIndex(SAPFOR::Argument* func_param, int max_index);
|
||||
1872
Sapfor/_src/CFGraph/RD_subst.cpp
Normal file
1872
Sapfor/_src/CFGraph/RD_subst.cpp
Normal file
File diff suppressed because it is too large
Load Diff
40
Sapfor/_src/CFGraph/RD_subst.h
Normal file
40
Sapfor/_src/CFGraph/RD_subst.h
Normal file
@@ -0,0 +1,40 @@
|
||||
#pragma once
|
||||
|
||||
#include<unordered_map>
|
||||
|
||||
#include "../Utils/SgUtils.h"
|
||||
#include "../Utils/CommonBlock.h"
|
||||
#include "../GraphCall/graph_calls.h"
|
||||
|
||||
#include "CFGraph.h"
|
||||
#include "IR.h"
|
||||
|
||||
inline bool hasStoreStructure(SAPFOR::CFG_OP type)
|
||||
{
|
||||
return (type == SAPFOR::CFG_OP::STORE) ||
|
||||
(type == SAPFOR::CFG_OP::REC_REF_STORE) ||
|
||||
(type == SAPFOR::CFG_OP::POINTER_ASS);
|
||||
}
|
||||
|
||||
const std::map<std::string, SgSymbol*>& getCommonArgsByFunc(FuncInfo* func, std::map<FuncInfo*, std::map<std::string, SgSymbol*>>& cache,
|
||||
const std::vector<std::pair<const Variable*, CommonBlock*>>& commonVars,
|
||||
std::unordered_map<SgSymbol*, std::string>& globals_cache,
|
||||
std::unordered_map<SgSymbol*, std::string>& locals_cache);
|
||||
|
||||
std::vector<SAPFOR::BasicBlock*> sortCfgNodes(const std::vector<SAPFOR::BasicBlock*>& blocks,
|
||||
std::set<std::pair<SAPFOR::BasicBlock*, SAPFOR::BasicBlock*>>* ignored_edges = NULL);
|
||||
|
||||
const std::string& getArgNameBySymbol(const std::vector<std::pair<const Variable*, CommonBlock*>>& commonVars,
|
||||
const FuncInfo* func, SgSymbol* s, std::unordered_map<SgSymbol*, std::string>& globals_cache,
|
||||
std::unordered_map<SgSymbol*, std::string>& locals_cache);
|
||||
|
||||
// main functions of SUBST_EXPR_RD pass
|
||||
void buildSubstitutions(const std::map<FuncInfo*, std::vector<SAPFOR::BasicBlock*>>& CFGraph_for_project, const std::map<std::string, CommonBlock*>& commonBlocks, SgProject* project);
|
||||
void performRDSubst(const std::map<FuncInfo*, std::vector<SAPFOR::BasicBlock*>>& CFGraph_for_project, const std::map<std::string, CommonBlock*>& commonBlocks, SgProject* project);
|
||||
void revertSubstitutions();
|
||||
|
||||
void cancelRevertionForStatement(std::string filename, SgStatement* stmt, int i);
|
||||
|
||||
/*void destroyReplacementsInFiles();
|
||||
void destroyOldExpressionsInFile();
|
||||
void destroyAllSubstitutionsData();*/
|
||||
761
Sapfor/_src/CFGraph/live_variable_analysis.cpp
Normal file
761
Sapfor/_src/CFGraph/live_variable_analysis.cpp
Normal file
@@ -0,0 +1,761 @@
|
||||
#include "live_variable_analysis.h"
|
||||
#include "RD_subst.h"
|
||||
#include "DataFlow/backward_data_flow.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <list>
|
||||
#include <unordered_map>
|
||||
#include <algorithm>
|
||||
|
||||
using std::string;
|
||||
using std::pair;
|
||||
using std::vector;
|
||||
using std::map;
|
||||
using std::set;
|
||||
using std::unordered_map;
|
||||
using std::list;
|
||||
|
||||
using LIVE_VARIABLES::LiveDeadVarsForCall;
|
||||
|
||||
namespace SAPFOR
|
||||
{
|
||||
bool BasicBlock::addLive(const map<SAPFOR::Argument*, vector<SAPFOR::BasicBlock*>>& to_add, bool in) {
|
||||
std::map<SAPFOR::Argument*, std::vector<SAPFOR::BasicBlock*>>& current_set = (in ? live_in : live_out);
|
||||
std::map<SAPFOR::Argument*, std::vector<SAPFOR::BasicBlock*>>& opposite_set = (!in ? live_in : live_out);
|
||||
|
||||
bool inserted = false;
|
||||
for (const auto& byNew : to_add)
|
||||
{
|
||||
const vector<SAPFOR::BasicBlock*>& add_in_live = byNew.second;
|
||||
vector<SAPFOR::BasicBlock*> new_in_live = {};
|
||||
|
||||
auto current_set_iter = current_set.find(byNew.first);
|
||||
|
||||
if (current_set_iter == current_set.end())
|
||||
new_in_live = add_in_live;
|
||||
else
|
||||
std::set_difference(add_in_live.begin(), add_in_live.end(), current_set_iter->second.begin(), current_set_iter->second.end(), std::inserter(new_in_live, new_in_live.begin()));
|
||||
|
||||
auto opposite_set_iter = opposite_set.find(byNew.first);
|
||||
auto both_set_iter = live_inout.find(byNew.first);
|
||||
|
||||
if (new_in_live.size() != 0)
|
||||
{
|
||||
inserted = true;
|
||||
|
||||
bool current_set_has_argument = current_set_iter != current_set.end();
|
||||
bool opposite_set_has_argument = opposite_set_iter != opposite_set.end();
|
||||
bool both_set_has_argument = both_set_iter != live_inout.end();
|
||||
|
||||
for (SAPFOR::BasicBlock* bb : new_in_live)
|
||||
{
|
||||
bool insert_to_both = false;
|
||||
if (opposite_set_has_argument)
|
||||
{
|
||||
auto& usages_from_opposite = opposite_set_iter->second;
|
||||
auto find_bb_from_opposite = std::lower_bound(usages_from_opposite.begin(), usages_from_opposite.end(), bb);
|
||||
|
||||
if (find_bb_from_opposite != usages_from_opposite.end() && *find_bb_from_opposite == bb)
|
||||
{
|
||||
insert_to_both = true;
|
||||
usages_from_opposite.erase(find_bb_from_opposite);
|
||||
|
||||
if (usages_from_opposite.size() == 0) {
|
||||
opposite_set.erase(opposite_set_iter);
|
||||
opposite_set_has_argument = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (insert_to_both)
|
||||
{
|
||||
if (!both_set_has_argument) {
|
||||
both_set_iter = live_inout.insert({ byNew.first, {} }).first;
|
||||
both_set_has_argument = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!current_set_has_argument) {
|
||||
current_set_iter = current_set.insert({ byNew.first, {} }).first;
|
||||
current_set_has_argument = true;
|
||||
}
|
||||
}
|
||||
|
||||
vector<SAPFOR::BasicBlock*>& dest = insert_to_both ? both_set_iter->second : current_set_iter->second;
|
||||
|
||||
auto find_bb_from_dest = std::lower_bound(dest.begin(), dest.end(), bb);
|
||||
|
||||
if (find_bb_from_dest == dest.end() || *find_bb_from_dest != bb)
|
||||
dest.insert(find_bb_from_dest, bb);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return inserted;
|
||||
}
|
||||
|
||||
bool BasicBlock::removeLive(SAPFOR::Argument* to_remove, bool in)
|
||||
{
|
||||
std::map<SAPFOR::Argument*, std::vector<SAPFOR::BasicBlock*>>& current_set = (in ? live_in : live_out);
|
||||
std::map<SAPFOR::Argument*, std::vector<SAPFOR::BasicBlock*>>& opposite_set = (!in ? live_in : live_out);
|
||||
|
||||
bool removed = false;
|
||||
|
||||
removed |= (current_set.erase(to_remove) != 0);
|
||||
|
||||
auto it = live_inout.find(to_remove);
|
||||
|
||||
if (it != live_inout.end())
|
||||
{
|
||||
auto& dest = opposite_set[to_remove];
|
||||
for (SAPFOR::BasicBlock* bb : it->second)
|
||||
{
|
||||
auto find_bb_from_dest = std::lower_bound(dest.begin(), dest.end(), bb);
|
||||
|
||||
if (find_bb_from_dest == dest.end() || *find_bb_from_dest != bb)
|
||||
dest.insert(find_bb_from_dest, bb);
|
||||
}
|
||||
|
||||
live_inout.erase(to_remove);
|
||||
removed = true;
|
||||
}
|
||||
|
||||
return removed;
|
||||
}
|
||||
|
||||
map<SAPFOR::Argument*, vector<SAPFOR::BasicBlock*>> BasicBlock::getLive(bool in) const {
|
||||
auto& current_set = in ? live_in : live_out;
|
||||
|
||||
map<SAPFOR::Argument*, vector<SAPFOR::BasicBlock*>> res;
|
||||
|
||||
for (auto& by_source : { current_set, live_inout })
|
||||
{
|
||||
for (auto& by_pair : by_source)
|
||||
{
|
||||
auto& dest = res[by_pair.first];
|
||||
auto dest_copy = dest;
|
||||
|
||||
dest.resize(dest_copy.size() + by_pair.second.size());
|
||||
|
||||
set_union(dest_copy.begin(), dest_copy.end(), by_pair.second.begin(), by_pair.second.end(), dest.begin());
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void BasicBlock::compressLives() {
|
||||
for (auto& bySrc : { &live_in, &live_out, &live_inout })
|
||||
for (auto& byArg : *bySrc)
|
||||
byArg.second.shrink_to_fit();
|
||||
}
|
||||
}
|
||||
|
||||
bool LiveDeadVarsForCall::tryInsert(set<SAPFOR::BasicBlock*>& dest, SAPFOR::BasicBlock* b)
|
||||
{
|
||||
if (b == block || dest.find(block) == dest.end())
|
||||
{
|
||||
dest.insert(b);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
LiveDeadVarsForCall::LiveDeadVarsForCall(FuncInfo* f, SAPFOR::BasicBlock* b, const vector<SAPFOR::Argument*>& p)
|
||||
{
|
||||
block = b;
|
||||
func = f;
|
||||
|
||||
int param_size = p.size();
|
||||
params = vector<SAPFOR::Argument*>(param_size, NULL);
|
||||
|
||||
for (int i = 0; i < param_size; i++)
|
||||
if (f->funcParams.isArgOut(i))
|
||||
params[i] = p[i];
|
||||
}
|
||||
|
||||
void LiveDeadVarsForCall::make_live(SAPFOR::Argument* arg, SAPFOR::BasicBlock* b)
|
||||
{
|
||||
if (arg->getMemType() == SAPFOR::CFG_MEM_TYPE::COMMON_ || arg->getMemType() == SAPFOR::CFG_MEM_TYPE::MODULE_)
|
||||
{
|
||||
if (commons_dead_after.find(arg) == commons_dead_after.end())
|
||||
tryInsert(commons_live_after[arg], b);
|
||||
}
|
||||
|
||||
auto it = find(params.begin(), params.end(), arg);
|
||||
if (it != params.end())
|
||||
{
|
||||
int idx = it - params.begin();
|
||||
if (dead_after.find(idx) == dead_after.end())
|
||||
tryInsert(live_after[idx], b);
|
||||
}
|
||||
}
|
||||
|
||||
void LiveDeadVarsForCall::make_dead(SAPFOR::Argument* arg)
|
||||
{
|
||||
if (arg->getMemType() == SAPFOR::CFG_MEM_TYPE::COMMON_ || arg->getMemType() == SAPFOR::CFG_MEM_TYPE::MODULE_)
|
||||
{
|
||||
if (commons_live_after.find(arg) == commons_live_after.end())
|
||||
commons_dead_after.insert(arg);
|
||||
}
|
||||
|
||||
auto it = find(params.begin(), params.end(), arg);
|
||||
if (it != params.end())
|
||||
{
|
||||
int idx = it - params.begin();
|
||||
if (live_after.find(idx) == live_after.end())
|
||||
dead_after.insert(idx);
|
||||
}
|
||||
}
|
||||
|
||||
void LiveDeadVarsForCall::updateFromOut()
|
||||
{
|
||||
for (const auto& p : block->getLiveOut())
|
||||
for (auto b : p.second)
|
||||
make_live(p.first, b);
|
||||
}
|
||||
|
||||
static bool getLiveDead(const vector<SAPFOR::Argument*>& params, const string& func_name,
|
||||
set<SAPFOR::Argument*>& live, set<SAPFOR::Argument*>& dead);
|
||||
|
||||
static void buildUseDef(SAPFOR::BasicBlock* block, set<SAPFOR::Argument*>& use, set<SAPFOR::Argument*>& def,
|
||||
vector<SAPFOR::Argument*>& formal_parameters, vector<LiveDeadVarsForCall>& fcalls,
|
||||
const map<string, FuncInfo*>& funcByName, bool interprocedural);
|
||||
|
||||
class LiveVarAnalysisNode : public DataFlowAnalysisNode<map<SAPFOR::Argument*, vector<SAPFOR::BasicBlock*>>> {
|
||||
private:
|
||||
set<SAPFOR::Argument*> live, dead;
|
||||
public:
|
||||
map<SAPFOR::Argument*, vector<SAPFOR::BasicBlock*>> getIn()
|
||||
{
|
||||
return getBlock()->getLiveOut();
|
||||
}
|
||||
|
||||
map<SAPFOR::Argument*, vector<SAPFOR::BasicBlock*>> getOut()
|
||||
{
|
||||
return getBlock()->getLiveIn();
|
||||
}
|
||||
|
||||
bool addIn(const map<SAPFOR::Argument*, vector<SAPFOR::BasicBlock*>>& data)
|
||||
{
|
||||
return getBlock()->addLiveOut(data);
|
||||
}
|
||||
|
||||
bool addOut(const map<SAPFOR::Argument*, vector<SAPFOR::BasicBlock*>>& data)
|
||||
{
|
||||
return getBlock()->addLiveIn(data);
|
||||
}
|
||||
|
||||
DATA_FLOW_UPD_STATUS forwardData(const map<SAPFOR::Argument*, vector<SAPFOR::BasicBlock*>>& data)
|
||||
{
|
||||
bool inserted = false;
|
||||
|
||||
for (const auto& byArg : data)
|
||||
if (live.find(byArg.first) == live.end() && dead.find(byArg.first) == dead.end())
|
||||
inserted |= getBlock()->addLiveIn({ byArg });
|
||||
|
||||
return inserted ? DATA_FLOW_UPD_STATUS::PROPAGATED : DATA_FLOW_UPD_STATUS::NO_CHANGE;
|
||||
}
|
||||
|
||||
LiveVarAnalysisNode(SAPFOR::BasicBlock* block, vector<SAPFOR::Argument*>& formal_parameters,
|
||||
vector<LiveDeadVarsForCall>& fcalls, const map<string, FuncInfo*>& funcByName)
|
||||
{
|
||||
setBlock(block);
|
||||
|
||||
buildUseDef(getBlock(), live, dead, formal_parameters, fcalls, funcByName, true);
|
||||
|
||||
for (SAPFOR::Argument* arg : live)
|
||||
getBlock()->addLiveIn({ { arg, { getBlock() } } });
|
||||
}
|
||||
};
|
||||
|
||||
class LiveVarAnalysis : public BackwardDataFlowAnalysis<LiveVarAnalysisNode> {
|
||||
protected:
|
||||
vector<SAPFOR::Argument*>& formal_parameters;
|
||||
vector<LiveDeadVarsForCall>& fcalls;
|
||||
const map<string, FuncInfo*>& funcByName;
|
||||
|
||||
LiveVarAnalysisNode* createNode(SAPFOR::BasicBlock* block) override {
|
||||
return new LiveVarAnalysisNode(block, formal_parameters, fcalls, funcByName);
|
||||
}
|
||||
public:
|
||||
LiveVarAnalysis(vector<SAPFOR::Argument*>& formal_parameters, vector<LiveDeadVarsForCall>& fcalls,
|
||||
const map<string, FuncInfo*>& funcByName) : formal_parameters(formal_parameters), fcalls(fcalls), funcByName(funcByName)
|
||||
{ }
|
||||
};
|
||||
|
||||
void getUseDefForInstruction(SAPFOR::BasicBlock* block, SAPFOR::Instruction* instr,
|
||||
set<SAPFOR::Argument*>& use, set<SAPFOR::Argument*>& def,
|
||||
vector<SAPFOR::Argument*>& formal_parameters, vector<LiveDeadVarsForCall>& fcalls,
|
||||
vector<SAPFOR::Argument*>& arg_stack, int& arg_stack_index, int& arg_stack_size,
|
||||
bool& last_stack_op,
|
||||
string& fName, const map<string, FuncInfo*>& funcByName, bool interprocedural)
|
||||
{
|
||||
for (auto arg : { instr->getArg1(), instr->getArg2(), instr->getResult() })
|
||||
if (arg && arg->getMemType() == SAPFOR::CFG_MEM_TYPE::FUNC_PARAM_)
|
||||
formal_parameters[getParamIndex(arg, formal_parameters.size())] = arg;
|
||||
|
||||
last_stack_op = false;
|
||||
SAPFOR::Argument* res_arg = NULL;
|
||||
|
||||
static const set<SAPFOR::CFG_OP> skip = { SAPFOR::CFG_OP::ENTRY };
|
||||
SAPFOR::CFG_OP instr_operation = instr->getOperation();
|
||||
if (instr_operation == SAPFOR::CFG_OP::F_CALL ||
|
||||
instr_operation == SAPFOR::CFG_OP::STORE ||
|
||||
instr_operation == SAPFOR::CFG_OP::LOAD)
|
||||
{
|
||||
res_arg = (instr_operation == SAPFOR::CFG_OP::STORE ? instr->getArg1() : instr->getResult());
|
||||
if(instr_operation != SAPFOR::CFG_OP::F_CALL)
|
||||
use.insert(instr_operation != SAPFOR::CFG_OP::STORE ? instr->getArg1() : instr->getResult());
|
||||
|
||||
arg_stack_size = stoi(instr->getArg2()->getValue());
|
||||
|
||||
arg_stack.clear();
|
||||
arg_stack.resize(arg_stack_size);
|
||||
|
||||
arg_stack_index = arg_stack_size - 1;
|
||||
|
||||
if(instr_operation == SAPFOR::CFG_OP::F_CALL)
|
||||
fName = instr->getArg1()->getValue();
|
||||
}
|
||||
else if (hasStoreStructure(instr_operation))
|
||||
{
|
||||
res_arg = instr->getArg1();
|
||||
set<SAPFOR::Argument*> instr_args = { instr->getResult(), instr->getArg2() };
|
||||
use.insert(instr_args.begin(), instr_args.end());
|
||||
}
|
||||
else if (instr_operation == SAPFOR::CFG_OP::PARAM || instr_operation == SAPFOR::CFG_OP::REF)
|
||||
{
|
||||
arg_stack[arg_stack_index--] = instr->getArg1();
|
||||
}
|
||||
else if (skip.find(instr_operation) == skip.end())
|
||||
{
|
||||
//default
|
||||
res_arg = instr->getResult();
|
||||
std::set<SAPFOR::Argument*> intr_args = { instr->getArg1(), instr->getArg2() };
|
||||
use.insert(intr_args.begin(), intr_args.end());
|
||||
}
|
||||
else
|
||||
{
|
||||
//skip
|
||||
return;
|
||||
}
|
||||
|
||||
if (arg_stack_index < 0) {
|
||||
if(instr_operation == SAPFOR::CFG_OP::PARAM || instr_operation == SAPFOR::CFG_OP::F_CALL)
|
||||
{
|
||||
auto func_it = funcByName.find(fName);
|
||||
if (interprocedural && func_it != funcByName.end())
|
||||
{
|
||||
fcalls.push_back(LiveDeadVarsForCall(func_it->second, block, arg_stack));
|
||||
|
||||
auto r_it = fcalls.rbegin();
|
||||
auto r_end = fcalls.rend();
|
||||
|
||||
for (auto e : def)
|
||||
r_it->make_dead(e);
|
||||
|
||||
for (auto e : use)
|
||||
r_it->make_live(e, block);
|
||||
}
|
||||
|
||||
set<SAPFOR::Argument*> make_live, make_dead;
|
||||
if (fName == "_READ")
|
||||
def.insert(arg_stack.begin(), arg_stack.end());
|
||||
else if (interprocedural && getLiveDead(arg_stack, fName, make_live, make_dead))
|
||||
{
|
||||
use.insert(make_live.begin(), make_live.end());
|
||||
def.insert(make_dead.begin(), make_dead.end());
|
||||
}
|
||||
else if (func_it != funcByName.end())
|
||||
{
|
||||
int arg_num = arg_stack.size();
|
||||
for (int i = 0; i < arg_num; i++)
|
||||
{
|
||||
if(func_it->second->funcParams.isArgOut(i))
|
||||
def.insert(arg_stack[i]);
|
||||
|
||||
if (func_it->second->funcParams.isArgIn(i))
|
||||
use.insert(arg_stack[i]);
|
||||
}
|
||||
}
|
||||
else
|
||||
use.insert(arg_stack.begin(), arg_stack.end());
|
||||
|
||||
fName = "";
|
||||
}
|
||||
else
|
||||
{
|
||||
use.insert(arg_stack.begin(), arg_stack.end());
|
||||
}
|
||||
|
||||
arg_stack_index = 0;
|
||||
arg_stack_size = 0;
|
||||
|
||||
arg_stack.clear();
|
||||
|
||||
last_stack_op = true;
|
||||
}
|
||||
|
||||
if (res_arg)
|
||||
def.insert(res_arg);
|
||||
}
|
||||
|
||||
static void updateUseDefForInstruction(SAPFOR::BasicBlock* block, SAPFOR::Instruction* instr,
|
||||
set<SAPFOR::Argument*>& use, set<SAPFOR::Argument*>& def,
|
||||
vector<SAPFOR::Argument*>& formal_parameters, vector<LiveDeadVarsForCall>& fcalls,
|
||||
vector<SAPFOR::Argument*>& arg_stack, int& arg_stack_index, int& arg_stack_size,
|
||||
string& fName, const map<string, FuncInfo*>& funcByName, bool interprocedural)
|
||||
{
|
||||
set<SAPFOR::Argument*> res, args;
|
||||
bool last_stack_op;
|
||||
getUseDefForInstruction(block, instr,
|
||||
args, res,
|
||||
formal_parameters, fcalls,
|
||||
arg_stack, arg_stack_index, arg_stack_size,
|
||||
last_stack_op,
|
||||
fName, funcByName,
|
||||
interprocedural
|
||||
);
|
||||
|
||||
for (auto e : res)
|
||||
{
|
||||
if (e && e->getType() == SAPFOR::CFG_ARG_TYPE::VAR)
|
||||
{
|
||||
def.insert(e);
|
||||
use.erase(e);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto e : args)
|
||||
{
|
||||
if (e && e->getType() == SAPFOR::CFG_ARG_TYPE::VAR)
|
||||
{
|
||||
use.insert(e);
|
||||
def.erase(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Build use and def sets of block. Result are stored in use and def
|
||||
static void buildUseDef(SAPFOR::BasicBlock* block, set<SAPFOR::Argument*>& use, set<SAPFOR::Argument*>& def,
|
||||
vector<SAPFOR::Argument*>& formal_parameters, vector<LiveDeadVarsForCall>& fcalls,
|
||||
const map<string, FuncInfo*>& funcByName, bool interprocedural)
|
||||
{
|
||||
vector<SAPFOR::Argument*> arg_stack;
|
||||
int arg_stack_index = 0, arg_stack_size = 0;
|
||||
string fName;
|
||||
|
||||
const auto& instructions = block->getInstructions();
|
||||
auto ir_block_it = instructions.rbegin(), ir_block_end = instructions.rend();
|
||||
|
||||
for (; ir_block_it != ir_block_end; ir_block_it++)
|
||||
{
|
||||
updateUseDefForInstruction(block, (*ir_block_it)->getInstruction(),
|
||||
use, def,
|
||||
formal_parameters, fcalls,
|
||||
arg_stack, arg_stack_index, arg_stack_size,
|
||||
fName, funcByName,
|
||||
interprocedural
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// prints info about live variables
|
||||
void doDumpLive(const map<FuncInfo*, vector<SAPFOR::BasicBlock*>>& CFGraph_for_project)
|
||||
{
|
||||
for (const auto& byFunc : CFGraph_for_project)
|
||||
{
|
||||
__spf_print(1, "============================================\n");
|
||||
__spf_print(1, "Live variables '%s' function\n", byFunc.first->funcName.c_str());
|
||||
__spf_print(1, "============================================\n");
|
||||
for (auto byBB : byFunc.second)
|
||||
{
|
||||
__spf_print(1, "[BB %d]\n", byBB->getNumber());
|
||||
__spf_print(1, " IN:\n");
|
||||
for (const auto& live : byBB->getLiveIn())
|
||||
{
|
||||
__spf_print(1, " %s:", live.first->getValue().c_str());
|
||||
for (auto use : live.second)
|
||||
__spf_print(1, " %d", use->getNumber());
|
||||
__spf_print(1, "\n");
|
||||
}
|
||||
|
||||
__spf_print(1, " OUT:\n");
|
||||
for (const auto& live : byBB->getLiveOut())
|
||||
{
|
||||
__spf_print(1, " %s:", live.first->getValue().c_str());
|
||||
for (auto use : live.second)
|
||||
__spf_print(1, " %d", use->getNumber());
|
||||
__spf_print(1, "\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// sets for the next function
|
||||
static map<string, pair<set<int>, set<SAPFOR::Argument*>>> live_by_func, dead_by_func;
|
||||
|
||||
// fill sets of arguments wich becomes live or dead after call of this function
|
||||
static void fillLiveDeadArgs(const FuncInfo* func, const vector<SAPFOR::BasicBlock*>& blocks)
|
||||
{
|
||||
if (blocks.size() == 0)
|
||||
return;
|
||||
|
||||
SAPFOR::BasicBlock* entrypoint = NULL;
|
||||
int entrypoint_first_instr = 0;
|
||||
set<SAPFOR::BasicBlock*> exits = {};
|
||||
|
||||
for (auto block : blocks)
|
||||
{
|
||||
if (block->getNext().size() == 0)
|
||||
exits.insert(block);
|
||||
|
||||
if (block->getInstructions().front()->isHeader())
|
||||
{
|
||||
if (!entrypoint || block->getInstructions()[0]->getNumber() < entrypoint_first_instr)
|
||||
{
|
||||
entrypoint_first_instr = block->getInstructions()[0]->getNumber();
|
||||
entrypoint = block;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!entrypoint)
|
||||
printInternalError(convertFileName(__FILE__).c_str(), __LINE__);
|
||||
|
||||
set<int> live, dead;
|
||||
set<SAPFOR::Argument*> common_live, common_dead;
|
||||
|
||||
for (const auto& arg : entrypoint->getLiveIn())
|
||||
{
|
||||
switch (arg.first->getMemType())
|
||||
{
|
||||
case SAPFOR::CFG_MEM_TYPE::COMMON_:
|
||||
case SAPFOR::CFG_MEM_TYPE::MODULE_:
|
||||
common_live.insert(arg.first);
|
||||
break;
|
||||
case SAPFOR::CFG_MEM_TYPE::FUNC_PARAM_:
|
||||
{
|
||||
int num = getParamIndex(arg.first, func->funcParams.countOfPars);
|
||||
if (func->funcParams.isArgIn(num))
|
||||
live.insert(num);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (auto byExit : exits)
|
||||
{
|
||||
for (const auto& byRd : byExit->getRD_Out())
|
||||
{
|
||||
auto out_arg = byRd.first;
|
||||
if (!(byRd.second.size() == 1 && *(byRd.second.begin()) < 0))
|
||||
{
|
||||
switch (out_arg->getMemType())
|
||||
{
|
||||
case SAPFOR::CFG_MEM_TYPE::COMMON_:
|
||||
case SAPFOR::CFG_MEM_TYPE::MODULE_:
|
||||
if (!common_live.count(out_arg))
|
||||
common_dead.insert(out_arg);
|
||||
break;
|
||||
case SAPFOR::CFG_MEM_TYPE::FUNC_PARAM_:
|
||||
{
|
||||
int num = getParamIndex(out_arg, func->funcParams.countOfPars);
|
||||
|
||||
if (!live.count(num) && func->funcParams.isArgOut(num))
|
||||
dead.insert(num);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
live_by_func[func->funcName] = { live, common_live };
|
||||
dead_by_func[func->funcName] = { dead, common_dead };
|
||||
}
|
||||
|
||||
// unite global arguments and actual parameters with given indexes for function
|
||||
// stores the result in the last argument
|
||||
bool joinGlobalsWithParameters(const vector<SAPFOR::Argument*>& params,
|
||||
const map<string, pair<set<int>, set<SAPFOR::Argument*>>>& params_and_globals,
|
||||
const string& func_name, set<SAPFOR::Argument*>& result)
|
||||
{
|
||||
auto globals_it = params_and_globals.find(func_name);
|
||||
|
||||
if (globals_it == params_and_globals.end())
|
||||
return false;
|
||||
|
||||
const auto& param_indexes = globals_it->second.first;
|
||||
const auto& globals = globals_it->second.second;
|
||||
|
||||
int params_size = params.size();
|
||||
|
||||
for (int idx : param_indexes)
|
||||
{
|
||||
if (idx < params_size) {
|
||||
if (params[idx] && params[idx]->getType() == SAPFOR::CFG_ARG_TYPE::VAR)
|
||||
result.insert(params[idx]);
|
||||
}
|
||||
else
|
||||
printInternalError(convertFileName(__FILE__).c_str(), __LINE__);
|
||||
}
|
||||
|
||||
result.insert(globals.begin(), globals.end());
|
||||
return true;
|
||||
}
|
||||
|
||||
// fill sets of arguments wich becomes live or dead after call with parameters params
|
||||
static bool getLiveDead(const vector<SAPFOR::Argument*>& params, const string& func_name,
|
||||
set<SAPFOR::Argument*>& live, set<SAPFOR::Argument*>& dead)
|
||||
{
|
||||
return joinGlobalsWithParameters(params, live_by_func, func_name, live) &&
|
||||
joinGlobalsWithParameters(params, dead_by_func, func_name, dead);
|
||||
}
|
||||
|
||||
// entrypoint for live variable analysis pass
|
||||
void runLiveVariableAnalysis(const map<FuncInfo*, vector<SAPFOR::BasicBlock*>>& CFGraph_for_project)
|
||||
{
|
||||
/*
|
||||
Here we assume that there is no recursive (explicit or implicit) calls.
|
||||
So it is easy to process CALL instruction: just use live_in set of first block
|
||||
for this function (that has already been built).
|
||||
*/
|
||||
|
||||
map<FuncInfo*, set<FuncInfo*>> callDeps;
|
||||
map<string, FuncInfo*> funcByName;
|
||||
|
||||
for (auto& byFunc : CFGraph_for_project)
|
||||
{
|
||||
callDeps[byFunc.first].insert(byFunc.first->callsFromV.begin(), byFunc.first->callsFromV.end());
|
||||
funcByName[byFunc.first->funcName] = byFunc.first;
|
||||
}
|
||||
|
||||
vector<set<FuncInfo*>> scc;
|
||||
vector<set<FuncInfo*>> callLvls = groupByCallDependencies(callDeps, scc);
|
||||
|
||||
map<string, LiveVarAnalysis*> func_to_analysis_object;
|
||||
map<string, vector<SAPFOR::Argument*>> func_to_parameters;
|
||||
|
||||
list<vector<LiveDeadVarsForCall>> live_for_fcalls;
|
||||
|
||||
//TODO: take into account ssc structure
|
||||
// main stage
|
||||
for (auto& byLvl : callLvls)
|
||||
{
|
||||
live_for_fcalls.push_front({});
|
||||
auto& curr_fcalls = live_for_fcalls.front();
|
||||
|
||||
for (auto& byFunc : byLvl)
|
||||
{
|
||||
auto itCFG = CFGraph_for_project.find(byFunc);
|
||||
if (itCFG == CFGraph_for_project.end())
|
||||
printInternalError(convertFileName(__FILE__).c_str(), __LINE__);
|
||||
|
||||
|
||||
auto& params = func_to_parameters[byFunc->funcName] = vector<SAPFOR::Argument*>(byFunc->funcParams.countOfPars, NULL);
|
||||
|
||||
LiveVarAnalysis* analysis_object = (func_to_analysis_object[byFunc->funcName] = new LiveVarAnalysis(params, curr_fcalls, funcByName));
|
||||
analysis_object->fit(itCFG->second);
|
||||
analysis_object->analyze();
|
||||
|
||||
fillLiveDeadArgs(byFunc, itCFG->second);
|
||||
}
|
||||
}
|
||||
|
||||
// interprocedural analysis
|
||||
for (auto& calls_vector : live_for_fcalls)
|
||||
{
|
||||
map<FuncInfo*, LiveDeadVarsForCall> assembled_fcalls;
|
||||
for (auto& call : calls_vector)
|
||||
{
|
||||
call.updateFromOut();
|
||||
call.params.clear();
|
||||
call.commons_dead_after.clear();
|
||||
call.dead_after.clear();
|
||||
|
||||
auto it = assembled_fcalls.find(call.func);
|
||||
if (it == assembled_fcalls.end())
|
||||
it = assembled_fcalls.insert({ call.func, LiveDeadVarsForCall(call.func, call.block, {}) }).first;
|
||||
|
||||
for (const auto& p : call.live_after)
|
||||
it->second.live_after[p.first].insert(p.second.begin(), p.second.end());
|
||||
|
||||
for (const auto& p : call.commons_live_after)
|
||||
it->second.commons_live_after[p.first].insert(p.second.begin(), p.second.end());
|
||||
}
|
||||
|
||||
for (const auto& func : assembled_fcalls)
|
||||
{
|
||||
auto func_it = func_to_analysis_object.find(func.first->funcName);
|
||||
if (func_it == func_to_analysis_object.end())
|
||||
printInternalError(convertFileName(__FILE__).c_str(), __LINE__);
|
||||
|
||||
auto param_it = func_to_parameters.find(func.first->funcName);
|
||||
if (param_it == func_to_parameters.end())
|
||||
printInternalError(convertFileName(__FILE__).c_str(), __LINE__);
|
||||
|
||||
const vector<SAPFOR::Argument*>& params = param_it->second;
|
||||
auto params_begin = params.begin(), params_end = params.end();
|
||||
|
||||
map<SAPFOR::Argument*, set<SAPFOR::BasicBlock*>> live_after = func.second.commons_live_after;
|
||||
|
||||
for (auto curr = params_begin; curr < params_end; curr++)
|
||||
{
|
||||
if (*curr)
|
||||
{
|
||||
const auto& live_param_it = func.second.live_after.find(curr - params_begin);
|
||||
if (live_param_it != func.second.live_after.end())
|
||||
live_after[*curr].insert(live_param_it->second.begin(), live_param_it->second.end());
|
||||
}
|
||||
}
|
||||
|
||||
set<LiveVarAnalysisNode*> exits;
|
||||
int max_cnt = LiveVarAnalysisNode::getStartCounter();
|
||||
for (auto block : func_it->second->getNodes())
|
||||
{
|
||||
if (block->getBlock()->getNext().size() == 0)
|
||||
exits.insert(block);
|
||||
if (block->getInCnt() > max_cnt)
|
||||
max_cnt = block->getInCnt();
|
||||
}
|
||||
|
||||
max_cnt++;
|
||||
|
||||
for (auto exit : exits)
|
||||
{
|
||||
for (const auto& byArg : live_after)
|
||||
{
|
||||
map<SAPFOR::Argument*, vector<SAPFOR::BasicBlock*>> converted;
|
||||
converted[byArg.first] = vector<SAPFOR::BasicBlock*>(byArg.second.begin(), byArg.second.end());
|
||||
|
||||
if (exit->addIn(converted))
|
||||
{
|
||||
exit->setInCnt(max_cnt);
|
||||
if (exit->forwardData(converted) != DATA_FLOW_UPD_STATUS::NO_CHANGE)
|
||||
exit->setOutCnt(max_cnt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// now we can update live sets in all blocks
|
||||
func_it->second->analyze();
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& byFunc : func_to_analysis_object)
|
||||
delete byFunc.second;
|
||||
|
||||
for (auto& byFunc : CFGraph_for_project)
|
||||
for (auto& byBlock : byFunc.second)
|
||||
byBlock->compressLives();
|
||||
|
||||
live_by_func.clear();
|
||||
dead_by_func.clear();
|
||||
}
|
||||
55
Sapfor/_src/CFGraph/live_variable_analysis.h
Normal file
55
Sapfor/_src/CFGraph/live_variable_analysis.h
Normal file
@@ -0,0 +1,55 @@
|
||||
#pragma once
|
||||
|
||||
#include "../Utils/SgUtils.h"
|
||||
#include "CFGraph.h"
|
||||
|
||||
namespace LIVE_VARIABLES
|
||||
{
|
||||
/* Store information about live and dead variables after call operator */
|
||||
/* (needed for interprocedural part of live variable analysis) */
|
||||
class LiveDeadVarsForCall
|
||||
{
|
||||
private:
|
||||
bool tryInsert(std::set<SAPFOR::BasicBlock*>& dest, SAPFOR::BasicBlock* b);
|
||||
public:
|
||||
FuncInfo* func;
|
||||
|
||||
std::map<int, std::set<SAPFOR::BasicBlock*>> live_after;
|
||||
std::set<int> dead_after;
|
||||
|
||||
std::map<SAPFOR::Argument*, std::set<SAPFOR::BasicBlock*>> commons_live_after;
|
||||
std::set<SAPFOR::Argument*> commons_dead_after;
|
||||
|
||||
std::vector<SAPFOR::Argument*> params;
|
||||
SAPFOR::BasicBlock* block;
|
||||
|
||||
LiveDeadVarsForCall(FuncInfo* f, SAPFOR::BasicBlock* b, const std::vector<SAPFOR::Argument*>& p);
|
||||
|
||||
void make_live(SAPFOR::Argument* arg, SAPFOR::BasicBlock* b);
|
||||
void make_dead(SAPFOR::Argument* arg);
|
||||
|
||||
void updateFromOut();
|
||||
};
|
||||
}
|
||||
|
||||
template <class IT, class DEST>
|
||||
void insertIfVar(IT begin, IT end, DEST& to) {
|
||||
for (auto it = begin; it != end; it++)
|
||||
if (*it && (*it)->getType() == SAPFOR::CFG_ARG_TYPE::VAR)
|
||||
to.insert(*it);
|
||||
}
|
||||
|
||||
void getUseDefForInstruction(SAPFOR::BasicBlock* block, SAPFOR::Instruction* instr,
|
||||
std::set<SAPFOR::Argument*>& use, std::set<SAPFOR::Argument*>& def,
|
||||
std::vector<SAPFOR::Argument*>& formal_parameters, std::vector<LIVE_VARIABLES::LiveDeadVarsForCall>& fcalls,
|
||||
std::vector<SAPFOR::Argument*>& arg_stack, int& arg_stack_index, int& arg_stack_size,
|
||||
bool& last_stack_op,
|
||||
std::string& fName, const std::map<std::string, FuncInfo*>& funcByName, bool interprocedural);
|
||||
|
||||
void runLiveVariableAnalysis(const std::map<FuncInfo*, std::vector<SAPFOR::BasicBlock*>>& CFGraph_for_project);
|
||||
|
||||
void doDumpLive(const std::map<FuncInfo*, std::vector<SAPFOR::BasicBlock*>>& CFGraph_for_project);
|
||||
|
||||
bool joinGlobalsWithParameters(const std::vector<SAPFOR::Argument*>& params,
|
||||
const std::map<std::string, std::pair<std::set<int>, std::set<SAPFOR::Argument*>>>& params_and_globals,
|
||||
const std::string& func_name, std::set<SAPFOR::Argument*>& result);
|
||||
539
Sapfor/_src/CFGraph/private_variables_analysis.cpp
Normal file
539
Sapfor/_src/CFGraph/private_variables_analysis.cpp
Normal file
@@ -0,0 +1,539 @@
|
||||
#include "../Utils/errors.h"
|
||||
#include "private_variables_analysis.h"
|
||||
#include "../GraphLoop/graph_loops.h"
|
||||
#include "../LoopAnalyzer/loop_analyzer.h"
|
||||
#include "../SageAnalysisTool/depGraph.h"
|
||||
#include "../DirectiveProcessing/directive_parser.h"
|
||||
#include "live_variable_analysis.h"
|
||||
#include "RD_subst.h"
|
||||
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <unordered_set>
|
||||
#include <unordered_map>
|
||||
#include <list>
|
||||
|
||||
using std::string;
|
||||
using std::wstring;
|
||||
using std::pair;
|
||||
using std::vector;
|
||||
using std::map;
|
||||
using std::set;
|
||||
using std::unordered_set;
|
||||
using std::unordered_map;
|
||||
using std::list;
|
||||
|
||||
static map<string, pair<set<int>, set<SAPFOR::Argument*>>> outForFunc;
|
||||
static unordered_map<SgSymbol*, string> global_cache, local_cache;
|
||||
|
||||
static unordered_map <SAPFOR::Argument*, SgSymbol*> argumentToSymbol;
|
||||
|
||||
#define DEBUG_PRINT_PRIVATE 0
|
||||
|
||||
#define PRINT_PRIVATES 1
|
||||
#define PRINT_WARNINGS 1
|
||||
// print privates and lastprivates for loop
|
||||
void printLoopInfo(const LoopGraph* loop)
|
||||
{
|
||||
SgForStmt* loop_stmt = isSgForStmt(loop->loop);
|
||||
|
||||
const set<string>& priv = loop->privateScalars;
|
||||
const set<string>& lastpriv = loop->lastprivateScalars;
|
||||
|
||||
if(!loop_stmt)
|
||||
printInternalError(convertFileName(__FILE__).c_str(), __LINE__);
|
||||
|
||||
__spf_print(PRINT_PRIVATES, " loop in file '%s' at line %d\n", loop->fileName.c_str(), loop->lineNum);
|
||||
__spf_print(PRINT_PRIVATES, " privates:");
|
||||
for(const auto& ident : priv)
|
||||
__spf_print(PRINT_PRIVATES, " %s", ident.c_str());
|
||||
__spf_print(PRINT_PRIVATES, "\n lastprivates:");
|
||||
for (const auto& ident : lastpriv)
|
||||
__spf_print(PRINT_PRIVATES, " %s", ident.c_str());
|
||||
__spf_print(PRINT_PRIVATES, "\n");
|
||||
|
||||
if (PRINT_WARNINGS)
|
||||
{
|
||||
set<string> added;
|
||||
for (auto& data : getAttributes<SgStatement*, SgStatement*>(loop_stmt, set<int>{ SPF_ANALYSIS_DIR }))
|
||||
fillPrivatesFromComment(new Statement(data), added);
|
||||
|
||||
|
||||
set<string> extra_old;
|
||||
std::set_difference(added.begin(), added.end(), priv.begin(), priv.end(), std::inserter(extra_old, extra_old.begin()));
|
||||
|
||||
if (extra_old.size() != 0)
|
||||
{
|
||||
__spf_print(PRINT_WARNINGS, " [WARNING] extra private variables:");
|
||||
for (const auto& ident : extra_old)
|
||||
__spf_print(PRINT_WARNINGS, " %s", ident.c_str());
|
||||
__spf_print(PRINT_WARNINGS, "\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check if parent statement contains stmt
|
||||
static bool isParentStmt(SgStatement* stmt, SgStatement* parent)
|
||||
{
|
||||
for (; stmt; stmt = stmt->controlParent())
|
||||
if (stmt == parent)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// iterate over expr tree and find SgSymbol that matches arg (by name)
|
||||
static SgSymbol* findSymbolByArgInExpression(const vector<pair<const Variable*, CommonBlock*>>& commonVars,
|
||||
const FuncInfo* func, const SAPFOR::Argument* arg, SgExpression* expr)
|
||||
{
|
||||
if (!expr)
|
||||
return NULL;
|
||||
|
||||
if (expr->symbol() && expr->symbol()->identifier() && getArgNameBySymbol(commonVars, func, expr->symbol(), global_cache, local_cache) == arg->getValue())
|
||||
return expr->symbol();
|
||||
|
||||
SgSymbol* left;
|
||||
if (left = findSymbolByArgInExpression(commonVars, func, arg, expr->lhs()))
|
||||
return left;
|
||||
|
||||
return findSymbolByArgInExpression(commonVars, func, arg, expr->rhs());
|
||||
}
|
||||
|
||||
// find SgSymbol that matches arg (by name) in stmt
|
||||
static SgSymbol* findSymbolByArgInStatement(const vector<pair<const Variable*, CommonBlock*>>& commonVars,
|
||||
const FuncInfo* func, const SAPFOR::Argument* arg, SgStatement* stmt)
|
||||
{
|
||||
if (!stmt)
|
||||
return NULL;
|
||||
|
||||
if (stmt->hasSymbol() && stmt->symbol() &&
|
||||
getArgNameBySymbol(commonVars, func, stmt->symbol(), global_cache, local_cache) == arg->getValue())
|
||||
{
|
||||
return stmt->symbol();
|
||||
}
|
||||
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
SgSymbol* found = findSymbolByArgInExpression(commonVars, func, arg, stmt->expr(i));
|
||||
if (found)
|
||||
return found;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// find SgSymbol for arg in instr's operator and fill argumentToSymbol
|
||||
// do nothing if arg already has found symbol
|
||||
static void addPlaceWithDef(const vector<pair<const Variable*, CommonBlock*>>& commonVars,
|
||||
const FuncInfo* func, SAPFOR::Argument* arg, SAPFOR::Instruction* instr) {
|
||||
if (argumentToSymbol.find(arg) != argumentToSymbol.end())
|
||||
return;
|
||||
|
||||
SgStatement* stmt_with_decl = instr->getOperator();
|
||||
if (!stmt_with_decl)
|
||||
return;
|
||||
|
||||
SgSymbol* found = findSymbolByArgInStatement(commonVars, func, arg, stmt_with_decl);
|
||||
|
||||
if (found)
|
||||
argumentToSymbol[arg] = found;
|
||||
|
||||
}
|
||||
|
||||
static void getDefined(const string& func, const vector<SAPFOR::Argument*>& params,
|
||||
set<SAPFOR::Argument*>& result)
|
||||
{
|
||||
if (!joinGlobalsWithParameters(params, outForFunc, func, result))
|
||||
{
|
||||
if (func == string("_WRITE") || isIntrinsic(func.c_str()))
|
||||
return;
|
||||
else //READ or else
|
||||
insertIfVar(params.begin(), params.end(), result);
|
||||
}
|
||||
}
|
||||
|
||||
static void fillOutForFunc(const FuncInfo* func, const vector<SAPFOR::BasicBlock*>& blocks)
|
||||
{
|
||||
if (blocks.size() == 0)
|
||||
return;
|
||||
|
||||
set<SAPFOR::BasicBlock*> exits = {};
|
||||
|
||||
for (auto block : blocks)
|
||||
{
|
||||
if (block->getNext().size() == 0)
|
||||
exits.insert(block);
|
||||
}
|
||||
|
||||
set<int> defined;
|
||||
set<SAPFOR::Argument*> common_defined;
|
||||
|
||||
for (auto byExit : exits)
|
||||
{
|
||||
for (const auto& byRd : byExit->getRD_Out())
|
||||
{
|
||||
auto out_arg = byRd.first;
|
||||
if (!(byRd.second.size() == 1 && *(byRd.second.begin()) < 0))
|
||||
{
|
||||
switch (out_arg->getMemType())
|
||||
{
|
||||
case SAPFOR::CFG_MEM_TYPE::COMMON_:
|
||||
case SAPFOR::CFG_MEM_TYPE::MODULE_:
|
||||
common_defined.insert(out_arg);
|
||||
break;
|
||||
case SAPFOR::CFG_MEM_TYPE::FUNC_PARAM_:
|
||||
{
|
||||
int num = getParamIndex(out_arg, func->funcParams.countOfPars);
|
||||
if(func->funcParams.isArgOut(num))
|
||||
defined.insert(num);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
outForFunc[func->funcName] = { defined, common_defined };
|
||||
}
|
||||
|
||||
static void getDefsFromBlock(SAPFOR::BasicBlock* block, set<SAPFOR::Argument*>& res,
|
||||
const vector<pair<const Variable*, CommonBlock*>>& commonVars,
|
||||
const FuncInfo* func)
|
||||
{
|
||||
vector<SAPFOR::Argument*> lastParamRef;
|
||||
|
||||
for (auto ir_block : block->getInstructions())
|
||||
{
|
||||
SAPFOR::Instruction* instr = ir_block->getInstruction();
|
||||
SAPFOR::CFG_OP instr_operation = instr->getOperation();
|
||||
if (instr_operation == SAPFOR::CFG_OP::PARAM)
|
||||
{
|
||||
SAPFOR::Argument* arg = instr->getArg1();
|
||||
if(arg->getType() == SAPFOR::CFG_ARG_TYPE::VAR)
|
||||
addPlaceWithDef(commonVars, func, arg, instr);
|
||||
|
||||
lastParamRef.push_back(arg);
|
||||
}
|
||||
else if (instr_operation == SAPFOR::CFG_OP::F_CALL)
|
||||
{
|
||||
int count = stoi(instr->getArg2()->getValue());
|
||||
if (lastParamRef.size() != count)
|
||||
printInternalError(convertFileName(__FILE__).c_str(), __LINE__);
|
||||
|
||||
const string& fName = instr->getArg1()->getValue();
|
||||
|
||||
getDefined(fName, lastParamRef, res);
|
||||
|
||||
lastParamRef.clear();
|
||||
}
|
||||
}
|
||||
|
||||
int first_instr_num = block->getInstructions().front()->getNumber();
|
||||
int last_instr_num = block->getInstructions().back()->getNumber();
|
||||
|
||||
for (const auto& def : block->getRD_Out())
|
||||
for (int place : def.second)
|
||||
if (place >= first_instr_num && place <= last_instr_num && def.first->getType() == SAPFOR::CFG_ARG_TYPE::VAR)
|
||||
{
|
||||
res.insert(def.first);
|
||||
addPlaceWithDef(commonVars, func, def.first, block->getInstructions()[place - first_instr_num]->getInstruction());
|
||||
}
|
||||
}
|
||||
|
||||
// recursively analyze FOR loops
|
||||
static set<SAPFOR::BasicBlock*> analyzeLoop(LoopGraph* loop, const set<SAPFOR::BasicBlock*>& blocks,
|
||||
const vector<pair<const Variable*, CommonBlock*>>& commonVars,
|
||||
const map<string, SgSymbol*>& commonArgs, FuncInfo* func,
|
||||
map<string, vector<Messages>>& messages)
|
||||
{
|
||||
if (!loop->isFor)
|
||||
printInternalError(convertFileName(__FILE__).c_str(), __LINE__); //should be called only with FOR loops
|
||||
|
||||
SgStatement* loop_operator = loop->loop->GetOriginal();
|
||||
|
||||
// find blocks related to the current loop
|
||||
set<SAPFOR::BasicBlock*> currentLoop = { };
|
||||
|
||||
/*
|
||||
service block that looks like
|
||||
_reg = _reg < _reg
|
||||
IF_FALSE _reg then goto ...
|
||||
*/
|
||||
SAPFOR::BasicBlock* head_block = NULL;
|
||||
|
||||
int loop_start = loop->lineNum, loop_end = loop->lineNumAfterLoop;
|
||||
for (auto bb : blocks)
|
||||
{
|
||||
if (!bb || (bb->getInstructions().size() == 0))
|
||||
continue;
|
||||
|
||||
SgStatement* first = bb->getInstructions().front()->getInstruction()->getOperator();
|
||||
SgStatement* last = bb->getInstructions().back()->getInstruction()->getOperator();
|
||||
|
||||
if (isParentStmt(first, loop_operator) && isParentStmt(last, loop_operator))
|
||||
{
|
||||
currentLoop.insert(bb);
|
||||
|
||||
if ((!head_block) && (first == loop_operator) && (last == loop_operator) &&
|
||||
(bb->getInstructions().size() == 2) &&
|
||||
(bb->getInstructions().back()->getInstruction()->getOperation() == SAPFOR::CFG_OP::JUMP_IF))
|
||||
{
|
||||
head_block = bb;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!head_block)
|
||||
printInternalError(convertFileName(__FILE__).c_str(), __LINE__);
|
||||
|
||||
// find blocks inside loop wich can lead to head_block
|
||||
list<SAPFOR::BasicBlock*> search_stack = { head_block };
|
||||
set<SAPFOR::BasicBlock*> cycleBody = { };
|
||||
|
||||
while (search_stack.size() > 0)
|
||||
{
|
||||
SAPFOR::BasicBlock* curr = search_stack.front();
|
||||
search_stack.pop_front();
|
||||
|
||||
if (cycleBody.insert(curr).second)
|
||||
for (auto next : curr->getPrev())
|
||||
if (currentLoop.count(next))
|
||||
search_stack.push_back(next);
|
||||
}
|
||||
|
||||
set<SAPFOR::Argument*> useValueInLoop = {};
|
||||
|
||||
for (const auto& use : head_block->getLiveIn())
|
||||
{
|
||||
for (SAPFOR::BasicBlock* place : use.second)
|
||||
{
|
||||
if (currentLoop.count(place))
|
||||
{
|
||||
useValueInLoop.insert(use.first);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
set<SAPFOR::Argument*> changeValueInLoop = { };
|
||||
set<SAPFOR::Argument*> changeValueOnExit = { };
|
||||
set<SAPFOR::Argument*> LiveWhenLoopEnds = { };
|
||||
|
||||
auto loop_it = currentLoop.begin();
|
||||
auto loop_end_it = currentLoop.end();
|
||||
|
||||
auto body_it = cycleBody.begin();
|
||||
auto body_end = cycleBody.end();
|
||||
|
||||
while ((loop_it != loop_end_it) && (body_it != body_end))
|
||||
{
|
||||
if (*loop_it == *body_it)
|
||||
{
|
||||
getDefsFromBlock(*loop_it, changeValueInLoop, commonVars, func);
|
||||
body_it++;
|
||||
}
|
||||
else
|
||||
getDefsFromBlock(*loop_it, changeValueOnExit, commonVars, func);
|
||||
loop_it++;
|
||||
}
|
||||
|
||||
if (body_it != body_end)
|
||||
printInternalError(convertFileName(__FILE__).c_str(), __LINE__);
|
||||
|
||||
for (; loop_it != loop_end_it; loop_it++)
|
||||
getDefsFromBlock(*loop_it, changeValueOnExit, commonVars, func);
|
||||
|
||||
|
||||
for (auto bb : currentLoop)
|
||||
{
|
||||
//fill LiveWhenLoopEnds
|
||||
bool has_next_outside_body = false;
|
||||
for (const auto& next : bb->getNext())
|
||||
{
|
||||
if (cycleBody.find(next) == cycleBody.end())
|
||||
{
|
||||
has_next_outside_body = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (has_next_outside_body)
|
||||
{
|
||||
for (const auto& use : bb->getLiveOut())
|
||||
for (SAPFOR::BasicBlock* place : use.second)
|
||||
if (currentLoop.count(place) == 0)
|
||||
{
|
||||
LiveWhenLoopEnds.insert(use.first);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
set<SAPFOR::Argument*> arg_private = {}, arg_lastprivate = {};
|
||||
|
||||
std::set_difference(changeValueInLoop.begin(), changeValueInLoop.end(),
|
||||
useValueInLoop.begin(), useValueInLoop.end(),
|
||||
std::inserter(arg_private, arg_private.begin()));
|
||||
|
||||
arg_private.insert(changeValueOnExit.begin(), changeValueOnExit.end());
|
||||
|
||||
std::set_intersection(arg_private.begin(), arg_private.end(),
|
||||
LiveWhenLoopEnds.begin(), LiveWhenLoopEnds.end(),
|
||||
std::inserter(arg_lastprivate, arg_lastprivate.begin()));
|
||||
|
||||
changeValueInLoop.clear();
|
||||
LiveWhenLoopEnds.clear();
|
||||
useValueInLoop.clear();
|
||||
|
||||
vector<const depNode*> sym_private;
|
||||
for (auto e : arg_private)
|
||||
{
|
||||
SgSymbol* arg_sym = NULL;
|
||||
|
||||
auto it = argumentToSymbol.find(e);
|
||||
if (it != argumentToSymbol.end())
|
||||
arg_sym = it->second;
|
||||
else if (e->getMemType() == SAPFOR::CFG_MEM_TYPE::COMMON_ || e->getMemType() == SAPFOR::CFG_MEM_TYPE::MODULE_)
|
||||
continue;
|
||||
|
||||
if (arg_sym && arg_sym->identifier())
|
||||
{
|
||||
if (arg_lastprivate.find(e) != arg_lastprivate.end())
|
||||
{
|
||||
loop->lastprivateScalars.insert(arg_sym->identifier());
|
||||
|
||||
const char* identifier = arg_sym->identifier();
|
||||
wstring messageE, messageR;
|
||||
__spf_printToLongBuf(messageE, L"add lastprivate scalar '%s' to loop on line %d", to_wstring(identifier).c_str(), loop->lineNum);
|
||||
__spf_printToLongBuf(messageR, R200, to_wstring(identifier).c_str(), loop->lineNum);
|
||||
|
||||
messages[loop->fileName].push_back(Messages(NOTE, loop->lineNum, messageR, messageE, 3002));
|
||||
}
|
||||
else
|
||||
{
|
||||
SgStatement* s = new SgStatement(0);
|
||||
s->setlineNumber(loop_start);
|
||||
|
||||
SgExpression* exp = new SgExpression(VAR_REF);
|
||||
exp->setSymbol(arg_sym);
|
||||
|
||||
sym_private.push_back(new depNode(s, s, exp, exp, 0, 0, NULL, NULL, 0));
|
||||
loop->privateScalars.insert(arg_sym->identifier());
|
||||
}
|
||||
}
|
||||
else
|
||||
printInternalError(convertFileName(__FILE__).c_str(), __LINE__);
|
||||
}
|
||||
|
||||
addPrivatesToLoops(loop, sym_private, { {loop_start, isSgForStmt(loop_operator)} }, messages[loop->fileName]);
|
||||
|
||||
for (const depNode* node : sym_private)
|
||||
{
|
||||
delete node->stmtin;
|
||||
delete node;
|
||||
}
|
||||
|
||||
arg_private.clear();
|
||||
arg_lastprivate.clear();
|
||||
|
||||
printLoopInfo(loop);
|
||||
return currentLoop;
|
||||
}
|
||||
|
||||
|
||||
static void recAnalyzeLoop(LoopGraph* loop, const set<SAPFOR::BasicBlock*>& blocks,
|
||||
const vector<pair<const Variable*, CommonBlock*>>& commonVars,
|
||||
const map<string, SgSymbol*>& commonArgs,
|
||||
FuncInfo* func, map<string, vector<Messages>>& messages)
|
||||
{
|
||||
const auto& loop_body = loop->isFor ? analyzeLoop(loop, blocks, commonVars, commonArgs, func, messages) : blocks;
|
||||
|
||||
for (const auto& inner_loop : loop->children)
|
||||
recAnalyzeLoop(inner_loop, loop_body, commonVars, commonArgs, func, messages);
|
||||
}
|
||||
|
||||
void runPrivateVariableAnalysis(const map<string, vector<LoopGraph*>>& loopGraph,
|
||||
const map<FuncInfo*, vector<SAPFOR::BasicBlock*>>& CFGraph_for_project,
|
||||
const map<string, CommonBlock*>& commonBlocks,
|
||||
map<string, vector<Messages>>& messages)
|
||||
{
|
||||
map<string, FuncInfo*> funcByName;
|
||||
for (const auto& byFunc : CFGraph_for_project)
|
||||
if (byFunc.first)
|
||||
funcByName[byFunc.first->funcName] = byFunc.first;
|
||||
|
||||
|
||||
//fill outForFunc
|
||||
for (const auto& byLoopFunc : loopGraph)
|
||||
{
|
||||
for (const auto& byLoop : byLoopFunc.second)
|
||||
{
|
||||
for (const auto& byFuncCall : byLoop->calls)
|
||||
{
|
||||
const string& fname = byFuncCall.first;
|
||||
if (outForFunc.find(fname) == outForFunc.end())
|
||||
{
|
||||
auto func_it = funcByName.find(fname);
|
||||
if (func_it != funcByName.end())
|
||||
{
|
||||
FuncInfo* func = func_it->second;
|
||||
auto cfg_it = CFGraph_for_project.find(func);
|
||||
if (cfg_it == CFGraph_for_project.end())
|
||||
printInternalError(convertFileName(__FILE__).c_str(), __LINE__);
|
||||
|
||||
fillOutForFunc(cfg_it->first, cfg_it->second);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
map<FuncInfo*, map<string, SgSymbol*>> commonArgsByFunc = { };
|
||||
for (const auto& byFile : loopGraph)
|
||||
{
|
||||
SgFile::switchToFile(byFile.first);
|
||||
|
||||
for (auto loop : byFile.second)
|
||||
{
|
||||
int loop_start = loop->lineNum, loop_end = loop->lineNumAfterLoop;
|
||||
|
||||
SgStatement* search_func = loop->loop->GetOriginal();
|
||||
|
||||
while (search_func && (!isSgProgHedrStmt(search_func)))
|
||||
search_func = search_func->controlParent();
|
||||
|
||||
if(!search_func)
|
||||
printInternalError(convertFileName(__FILE__).c_str(), __LINE__); //loop statement outside any function statement
|
||||
|
||||
bool loop_analyzed = false;
|
||||
for (const auto& byFunc : CFGraph_for_project)
|
||||
{
|
||||
if (byFunc.first->fileName == byFile.first && byFunc.first->funcPointer->GetOriginal() == search_func)
|
||||
{
|
||||
const auto& commonVars = getCommonsByFunction(current_file, byFunc.first->funcPointer, commonBlocks);
|
||||
const auto& commonArgs = getCommonArgsByFunc(byFunc.first, commonArgsByFunc, commonVars, global_cache, local_cache);
|
||||
|
||||
set<SAPFOR::BasicBlock*> loop_ir;
|
||||
loop_ir.insert(byFunc.second.begin(), byFunc.second.end());
|
||||
recAnalyzeLoop(loop, loop_ir, commonVars, commonArgs, byFunc.first, messages);
|
||||
argumentToSymbol.clear(); //clear cache
|
||||
loop_analyzed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(!loop_analyzed)
|
||||
printInternalError(convertFileName(__FILE__).c_str(), __LINE__); //no func found for loop
|
||||
}
|
||||
|
||||
local_cache.clear();
|
||||
commonArgsByFunc.clear();
|
||||
}
|
||||
|
||||
outForFunc.clear();
|
||||
global_cache.clear();
|
||||
}
|
||||
11
Sapfor/_src/CFGraph/private_variables_analysis.h
Normal file
11
Sapfor/_src/CFGraph/private_variables_analysis.h
Normal file
@@ -0,0 +1,11 @@
|
||||
#include "../Utils/SgUtils.h"
|
||||
#include "../GraphLoop/graph_loops.h"
|
||||
#include "CFGraph.h"
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
void runPrivateVariableAnalysis(const std::map<std::string, std::vector<LoopGraph*>>& loopGraph,
|
||||
const std::map<FuncInfo*, std::vector<SAPFOR::BasicBlock*>>& CFGraph_for_project,
|
||||
const std::map<std::string, CommonBlock*>& commonBlocks,
|
||||
std::map<std::string, std::vector<Messages>>& messages);
|
||||
Reference in New Issue
Block a user