ROSE 编译器框架/活跃性分析
ROSE 中有几种活跃性分析的实现。
编译器执行的经典数据流分析,用于计算每个程序点可能在下次写入之前读取的变量,即每个程序点出口处的活动变量。
- 后向数据流分析
- 可能分析
Instructions Live_in vars
a
b = a + 2
b,a // step 3: b is used (live), a is used (live), c is killed
c = b * b
a,c // step 2: a,b,c , b is killed (defined), live_in ={a,c}
b = c + 1
b,a // step 1: start from the end of CFG here, a, b are used (live_in)
return b * a
另一个
L1: b := 3; // live_out={b}
L2: c := 5; // live_out ={b,c}
L3: a := b + c;
END
第 L2 行的活动变量集为 {b, c},但第 L1 行的活动变量集仅为 {b},因为变量 c 在第 2 行更新。变量 a 的值从未使用过,因此该变量从未处于活动状态。
- x 在循环之前不是活动变量(活动变量输入):x=a[i] 在 x 被使用之前重新定义了 x,x 在循环之后不是活动变量(活动变量输出):x=10 在 x 被使用之前重新定义了 x。
int x;
for (i=0;i<100;i++)
{
x= a[i];
b[i]=x+1;
}
x = 10;
- a 是活动变量输入和活动变量输出
int a[100];
void foo ()
{
// a is live-in: =a[i]+1 uses a.
for (i=0;i<100;i++)
{
a[i]=a[i]+1;
}
// A[] is be live-out, used after the loop
.. = a[i]
// A[] may be live-out, global variable, could be modified by other functions
}
- x 是活动变量输入,但不是活动变量输出
int x=1
for (i=0;i<100;i++)
{
// x is live-in, used before any redefinition.
b[i]=x+1;
x=...
... =x
}
// x is not live-out: redefined before any use
x = ...
您必须使用 https://github.com/rose-compiler/rose-develop 中的最新版本的 ROSE
cd rosebuildtree/projects/CodeThorn/src // 注意:必须进入 src 目录,而不是 CodeThorn 的顶部!
make analyterix
./analyterix --lv-analysis myprog.C
在 rose_myprog.C 中,lv-analysis 结果被注释为注释。
注意
- 直接在 projects/CodeThorn 下输入 make 将失败,因为它构建了所有内容,需要一个名为 SPOT 的第三方库
输入
...
#define MSIZE 200
int n, m, mits;
double tol, relax = 1.0, alpha = 0.0543;
double u[MSIZE][MSIZE], f[MSIZE][MSIZE], uold[MSIZE][MSIZE];
double dx, dy;
....
void
initialize ()
{
int i, j, xx, yy;
// double PI = 3.1415926;
dx = 2.0 / (n - 1); // -->dx@112:2
dy = 2.0 / (m - 1); //-->dy@113:2
/* Initialize initial condition and RHS */
//#pragma omp parallel for private(i,j,xx,yy)
for (i = 0; i < n; i++)
for (j = 0; j < m; j++)
{
xx = (int) (-1.0 + dx * (i - 1)); /* -1 < x < 1 */
yy = (int) (-1.0 + dy * (j - 1)); /* -1 < y < 1 */
u[i][j] = 0.0;
f[i][j] = -1.0 * alpha * (1.0 - xx * xx) * (1.0 - yy * yy)
- 2.0 * (1.0 - xx * xx) - 2.0 * (1.0 - yy * yy);
}
}
输出
void initialize()
// 84 lv-analysis-out: {n_56,m_57,mits_58,tol_59,relax_60,alpha_61,u_62,f_63,uold_64}
{
// 87 lv-analysis-out: {n_56,m_57,mits_58,tol_59,relax_60,alpha_61,u_62,f_63,uold_64}
int i;
// 87 lv-analysis-in : {n_56,m_57,mits_58,tol_59,relax_60,alpha_61,u_62,f_63,uold_64}
// 88 lv-analysis-out: {n_56,m_57,mits_58,tol_59,relax_60,alpha_61,u_62,f_63,uold_64}
int j;
// 88 lv-analysis-in : {n_56,m_57,mits_58,tol_59,relax_60,alpha_61,u_62,f_63,uold_64}
// 89 lv-analysis-out: {n_56,m_57,mits_58,tol_59,relax_60,alpha_61,u_62,f_63,uold_64}
int xx;
// 89 lv-analysis-in : {n_56,m_57,mits_58,tol_59,relax_60,alpha_61,u_62,f_63,uold_64}
// 90 lv-analysis-out: {n_56,m_57,mits_58,tol_59,relax_60,alpha_61,u_62,f_63,uold_64}
int yy;
// 90 lv-analysis-in : {n_56,m_57,mits_58,tol_59,relax_60,alpha_61,u_62,f_63,uold_64}
// double PI = 3.1415926;
// -->dx@112:2
// 91 lv-analysis-out: {n_56,m_57,mits_58,tol_59,relax_60,alpha_61,u_62,f_63,uold_64}
dx = 2.0 / (n - 1);
// 91 lv-analysis-in : {n_56,m_57,mits_58,tol_59,relax_60,alpha_61,u_62,f_63,uold_64,dx_65}
//-->dy@113:2
// 92 lv-analysis-out: {n_56,m_57,mits_58,tol_59,relax_60,alpha_61,u_62,f_63,uold_64,dx_65}
dy = 2.0 / (m - 1);
// 92 lv-analysis-in : {n_56,m_57,mits_58,tol_59,relax_60,alpha_61,u_62,f_63,uold_64,dx_65,dy_66}
/* Initialize initial condition and RHS */
//#pragma omp parallel for private(i,j,xx,yy)
// 93 lv-analysis-out: bot
for (
// 94 lv-analysis-out: {n_56,m_57,mits_58,tol_59,relax_60,alpha_61,u_62,f_63,uold_64,dx_65,dy_66}
i = 0
// 94 lv-analysis-in : {n_56,m_57,mits_58,tol_59,relax_60,alpha_61,u_62,f_63,uold_64,dx_65,dy_66,i_67}
;
// 95 lv-analysis-out: {n_56,m_57,mits_58,tol_59,relax_60,alpha_61,u_62,f_63,uold_64,dx_65,dy_66,i_67}
i < n;
// 95 lv-analysis-in : {n_56,m_57,mits_58,tol_59,relax_60,alpha_61,u_62,f_63,uold_64,dx_65,dy_66,i_67}
i++)
// 97 lv-analysis-out: bot
for (
// 98 lv-analysis-out: {n_56,m_57,mits_58,tol_59,relax_60,alpha_61,u_62,f_63,uold_64,dx_65,dy_66,i_67}
j = 0
// 98 lv-analysis-in : {n_56,m_57,mits_58,tol_59,relax_60,alpha_61,u_62,f_63,uold_64,dx_65,dy_66,i_67,j_68}
;
// 99 lv-analysis-out: {n_56,m_57,mits_58,tol_59,relax_60,alpha_61,u_62,f_63,uold_64,dx_65,dy_66,i_67,j_68}
j < m;
// 99 lv-analysis-in : {n_56,m_57,mits_58,tol_59,relax_60,alpha_61,u_62,f_63,uold_64,dx_65,dy_66,i_67,j_68}
j++) {
/* -1 < x < 1 */
// 102 lv-analysis-out: {n_56,m_57,mits_58,tol_59,relax_60,alpha_61,uold_64,dx_65,dy_66,i_67,j_68}
xx = ((int )(- 1.0 + dx * (i - 1)));
// 102 lv-analysis-in : {n_56,m_57,mits_58,tol_59,relax_60,alpha_61,uold_64,dx_65,dy_66,i_67,j_68,xx_69}
/* -1 < y < 1 */
// 103 lv-analysis-out: {n_56,m_57,mits_58,tol_59,relax_60,alpha_61,uold_64,dx_65,dy_66,i_67,j_68,xx_69}
yy = ((int )(- 1.0 + dy * (j - 1)));
// 103 lv-analysis-in : {n_56,m_57,mits_58,tol_59,relax_60,alpha_61,uold_64,dx_65,dy_66,i_67,j_68,xx_69,yy_70}
// 104 lv-analysis-out: {n_56,m_57,mits_58,tol_59,relax_60,alpha_61,uold_64,dx_65,dy_66,i_67,j_68,xx_69,yy_70}
u[i][j] = 0.0;
// 104 lv-analysis-in : {n_56,m_57,mits_58,tol_59,relax_60,alpha_61,u_62,uold_64,dx_65,dy_66,i_67,j_68,xx_69,yy_70}
// 105 lv-analysis-out: {n_56,m_57,mits_58,tol_59,relax_60,alpha_61,u_62,uold_64,dx_65,dy_66,i_67,j_68,xx_69,yy_70}
f[i][j] = - 1.0 * alpha * (1.0 - (xx * xx)) * (1.0 - (yy * yy)) - 2.0 * (1.0 - (xx * xx)) - 2.0 * (1.0 - (yy * yy));
// 105 lv-analysis-in : {n_56,m_57,mits_58,tol_59,relax_60,alpha_61,u_62,f_63,uold_64,dx_65,dy_66,i_67,j_68}
}
// 97 lv-analysis-in : bot
// 93 lv-analysis-in : bot
}
src/midend/abstractLayer/Labeler.h /.C // 带标签的 AST 节点
projects/CodeThorn/src/LVLattice.h // 活跃性分析格
这将被逐步淘汰,以支持更新的版本
提供两个函数来调用分析并获取循环的活动变量。
// Call liveness analysis on an entire project. LivenessAnalysis * SageInterface::call_liveness_analysis (SgProject *project, bool debug=false) // get liveIn and liveOut variables for a for loop from liveness analysis result liv. void getLiveVariables (LivenessAnalysis *liv, SgForStatement *loop, std::set< SgInitializedName * > &liveIns, std::set< SgInitializedName * > &liveOuts)
如果您想将其扩展到支持任何范围语句,则需要了解一些内部机制
//!Get liveIn and liveOut variables for a for loop
void SageInterface::getLiveVariables(LivenessAnalysis * liv, SgForStatement* loop, std::set<SgInitializedName*>& liveIns, std::set<SgIn
itializedName*> & liveOuts)
{
ROSE_ASSERT(liv != NULL);
ROSE_ASSERT(loop != NULL);
SgForStatement *forstmt = loop;
std::vector<SgInitializedName*> liveIns0, liveOuts0; // store the original one
// Jeremiah's hidden constructor parameter value '2' to grab the node for forStmt's
// Several CFG nodes are used for the same SgForStatement, only one of the is needed.
// We have to check the full control flow graph to find all SgForStatement's nodes,
// check the index numbers from 0 , find the one with two out edges (true, false)
// The CFG node should have a caption like" <SgForStatement> @ 8: 1",
// which means this is a CFG node for a for statement at source line 8, with an index 1.
// For SgForStatement, there are 5 cfg nodes, 0 and 4 are for begin and end CFG nodes
// 1: after init statement, 2: after test expression (the remaining one after filtering), 3: before increment
CFGNode cfgnode(forstmt,2);
FilteredCFGNode<IsDFAFilter> filternode= FilteredCFGNode<IsDFAFilter> (cfgnode);
// This one does not return the one we want even its getNode returns the
// right for statement
//FilteredCFGNode<IsDFAFilter> filternode= FilteredCFGNode<IsDFAFilter> (forstmt->cfgForBeginning());
ROSE_ASSERT(filternode.getNode()==forstmt);
// Check out edges
vector<FilteredCFGEdge < IsDFAFilter > > out_edges = filternode.outEdges();
ROSE_ASSERT(out_edges.size()==2);
vector<FilteredCFGEdge < IsDFAFilter > >::iterator iter= out_edges.begin();
for (; iter!=out_edges.end();iter++)
{
FilteredCFGEdge < IsDFAFilter > edge= *iter;
//SgForStatement should have two outgoing edges based on the loop condition
// one true(going into the loop body) and one false (going out the loop)
//x. Live-in (loop) = live-in (first-stmt-in-loop)
if (edge.condition()==eckTrue)
{
SgNode* firstnode= edge.target().getNode();
liveIns0 = liv->getIn(firstnode);
// cout<<"Live-in variables for loop:"<<endl;
for (std::vector<SgInitializedName*>::iterator iter = liveIns0.begin();
iter!=liveIns0.end(); iter++)
{
// SgInitializedName* name = *iter;
liveIns.insert(*iter);
// cout<< name->get_qualified_name().getString()<<endl;
}
}
//x. live-out(loop) = live-in (first-stmt-after-loop)
else if (edge.condition()==eckFalse)
{
SgNode* firstnode= edge.target().getNode();
liveOuts0 = liv->getIn(firstnode);
// cout<<"Live-out variables for loop:"<<endl;
for (std::vector<SgInitializedName*>::iterator iter = liveOuts0.begin();
iter!=liveOuts0.end(); iter++)
{
// SgInitializedName* name = *iter;
// cout<< name->get_qualified_name().getString()<<endl;
liveOuts.insert(*iter);
}
}
else
{
cerr<<"Unexpected CFG out edge type for SgForStmt!"<<endl;
ROSE_ASSERT(false);
}
} // end for (edges)
}
src/midend/programAnalysis/defUseAnaysis/LivenessAnalysis.cpp
/******************************************
* Algorithm used:
* for all n, in[n] = out[n] = 0
* w = { set of all nodes }
* repeat until w empty
* n = w.pop()
* out[n] = OR (n' ELEM SUCC[n]) in[n']
* in[n] = use[n] OR (out[n] - def[n])
* if change to in[n]
* for all predecessors m of n, w.push(m)
*****************************************/
buildtree/tests/roseTests/programAnalysisTests/variableLivenessTests/
runTest inputcode.c
将生成一些点文件
- cfg.dot
- dfa.dot
- var.dot // 这是变量显示的那个
用于生成点图的编程 API
#include "rose.h"
#include "DefUseAnalysis.h"
#include "LivenessAnalysis.h"
.....
SgProject* project = frontend(argvList);
// Call the Def-Use Analysis
DFAnalysis* defuse = new DefUseAnalysis(project);
int val = defuse->run(debug);
LivenessAnalysis* liv = new LivenessAnalysis(debug,(DefUseAnalysis*)defuse);
std::vector <FilteredCFGNode < IsDFAFilter > > dfaFunctions;
NodeQuerySynthesizedAttributeType vars = NodeQuery::querySubTree(project, V_SgFunctionDefinition);
NodeQuerySynthesizedAttributeType::const_iterator i = vars.begin();
bool abortme=false;
for (; i!=vars.end();++i) {
SgFunctionDefinition* func = isSgFunctionDefinition(*i);
std::string name = func->class_name();
string funcName = func->get_declaration()->get_qualified_name().str();
// run liveness analysis on all function bodies.
FilteredCFGNode <IsDFAFilter> rem_source = liv->run(func,abortme);
if (abortme)
break;
if (funcName!=funcParamName) {
if (debug)
cerr << " .. skipping live analysis check for func : " << funcName << endl;
continue;
}
if (rem_source.getNode()!=NULL)
dfaFunctions.push_back(rem_source);
std::ofstream f2("var.dot");
dfaToDot(f2, string("var"), dfaFunctions, (DefUseAnalysis*)defuse, liv);
f2.close();
// internals of returned CFG node after run()
// add this node to worklist and work through the outgoing edges
FilteredCFGNode<IsDFAFilter> source = FilteredCFGNode<IsDFAFilter> (
funcDecl->cfgForEnd());
if (forwardAlgo)
source = FilteredCFGNode<IsDFAFilter> (funcDecl->cfgForBeginning());
//CFGNode cmpSrc = CFGNode(funcDecl->cfgForEnd());
FilteredCFGNode<IsDFAFilter> rem_source = source;
sourcetree/src/midend/programAnalysis/defUseAnalysis
dfaToDot.h dfaToDot.cpp
两个步骤
- 将所有 CFG 节点收集到一个多重映射中:template <typename NodeT, typename EdgeT> void DfaToDotImpl<NodeT, EdgeT>::explore(NodeT n)
- 打印节点和边:template <typename NodeT, typename EdgeT> void DfaToDotImpl<NodeT, EdgeT>::processNodes(SgNode*)
待办事项
- 写入点图在中间不起作用