blob: 1de747067d2fb0e3f1817ffc08c30f80001f9089 [file] [log] [blame]
/**********************************************************************
* Copyright (c) 2007 IBM Corporation.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.ptp.pldt.mpi.analysis.analysis;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import org.eclipse.cdt.core.dom.ast.*;
import org.eclipse.cdt.core.dom.ast.c.ICASTDesignatedInitializer;
import org.eclipse.cdt.core.dom.ast.c.ICASTTypeIdInitializerExpression;
import org.eclipse.cdt.core.dom.ast.gnu.c.ICASTKnRFunctionDeclarator;
import org.eclipse.cdt.internal.core.dom.parser.IASTAmbiguousExpression;
import org.eclipse.ptp.pldt.mpi.analysis.cdt.graphs.IBlock;
import org.eclipse.ptp.pldt.mpi.analysis.cdt.graphs.ICallGraph;
import org.eclipse.ptp.pldt.mpi.analysis.cdt.graphs.ICallGraphNode;
import org.eclipse.ptp.pldt.mpi.analysis.cdt.graphs.IControlFlowGraph;
/**
* Calculate the (inter-procedural) use set and def set of each block.
* @author Yuan Zhang
*
*/
public class UseDefBuilder extends ASTVisitor{
protected ICallGraph cg_;
protected IControlFlowGraph cfg_ = null;
protected List<String> use_ = null;
protected List<String> def_ = null;
protected List<String> guse_ = null;
protected List<String> gdef_ = null;
protected List<String> padef_ = null;
protected final int lhs = 0;
protected final int rhs = 1;
protected MPICallGraphNode currentFunc_;
protected Hashtable<String,List<IBlock>> defTable_ = null;
public UseDefBuilder(ICallGraph cg){
cg_ = cg;
}
public void run(){
this.shouldVisitDeclarations = true;
this.shouldVisitExpressions = true;
this.shouldVisitStatements = true;
/* Fix point to deal with the recursion */
boolean change = true;
while(change){
change = false;
for(ICallGraphNode n = cg_.botEntry(); n != null; n = n.botNext()){
MPICallGraphNode node = (MPICallGraphNode)n;
//if(node.getFuncName().equals("yytnamerr"))
//System.out.println(node.getFuncName());
if(!node.marked) continue;
List<String> oldguse_ = node.getGlobalUse();
List<String> oldgdef_ = node.getGlobalDef();
List<String> oldpadef_ = node.getParamDef();
guse_ = new ArrayList<String>();
gdef_ = new ArrayList<String>();
padef_ = new ArrayList<String>();
cfg_ = node.getCFG();
currentFunc_ = node;
for(IBlock b = cfg_.getEntry().topNext(); b != null; b = b.topNext()){
MPIBlock block = (MPIBlock)b;
IASTNode content = block.getContent();
if(content == null || content instanceof IASTName) continue;
List<String> olduse_ = block.getUse();
List<String> olddef_ = block.getDef();
use_ = new ArrayList<String>();
def_ = new ArrayList<String>();
if(content instanceof IASTExpression){
IASTExpression expr = (IASTExpression)content;
expr.accept(this);
} else { //statement
IASTStatement stmt = (IASTStatement)content;
stmt.accept(this);
}
if(!Util.equals(use_, olduse_)){
block.setUse(use_);
change = true;
}
if(!Util.equals(def_, olddef_)){
block.setDef(def_);
change = true;
}
}
if(!Util.equals(guse_, oldguse_)){
node.setGlobalUse(guse_);
change = true;
}
if(!Util.equals(gdef_, oldgdef_)){
node.setGlobalDef(gdef_);
change = true;
}
if(!Util.equals(padef_, oldpadef_)){
node.setParamDef(padef_);
change = true;
}
}
}
for(ICallGraphNode n = cg_.botEntry(); n != null; n = n.botNext()){
MPICallGraphNode node = (MPICallGraphNode)n;
if(!node.marked) continue;
currentFunc_ = node;
cfg_ = node.getCFG();
setEntryBlock((MPIBlock)node.getCFG().getEntry());
setExitBlock((MPIBlock)node.getCFG().getExit());
defTable_ = new Hashtable<String,List<IBlock>>();
for(IBlock b = cfg_.getEntry(); b != null; b = b.topNext()){
MPIBlock block = (MPIBlock)b;
List<String> def = block.getDef();
if(def.isEmpty()) continue;
for(Iterator<String> i = def.iterator(); i.hasNext();){
String var = i.next();
List<IBlock> defblocks = defTable_.get(var);
if(defblocks == null){
defblocks = new ArrayList<IBlock>();
defblocks.add(block);
defTable_.put(var, defblocks);
} else {
defblocks.add(block);
defTable_.put(var, defblocks);
}
}
}
node.setDefTable(defTable_);
}
}
public int visit(IASTStatement stmt){
if(stmt instanceof IASTDeclarationStatement){
IASTDeclarationStatement declStmt = (IASTDeclarationStatement)stmt;
IASTDeclaration decl = declStmt.getDeclaration();
if(decl instanceof IASTSimpleDeclaration){
IASTSimpleDeclaration simpleDecl = (IASTSimpleDeclaration)decl;
IASTDeclarator[] declarators = simpleDecl.getDeclarators();
for(int i=0; i<declarators.length; i++){
IASTName name = declarators[i].getName();
IASTInitializer init = declarators[i].getInitializer();
if(init != null)
def_.add(name.toString());
processInitializer(init);
}
}
return PROCESS_SKIP;
}
return PROCESS_CONTINUE;
}
private void processInitializer(IASTInitializer init){
if(init != null){
if(init instanceof IASTInitializerExpression){
IASTInitializerExpression initE = (IASTInitializerExpression)init;
IASTExpression e = initE.getExpression();
useDefSet(e, rhs, null, -1);
}
else if(init instanceof IASTInitializerList){
IASTInitializerList list = (IASTInitializerList)init;
IASTInitializer[] inits = list.getInitializers();
for(int j = 0; j<inits.length; j++){
processInitializer(inits[j]);
}
}
else if(init instanceof ICASTDesignatedInitializer){
System.out.println("ICASTDesignatedInitializer found !"); //$NON-NLS-1$
}
}
}
/**
* The traverse is stopped (by PROCESS_SKIP) when the expression of
* the statement is visited. This method is used to find the expression.
*/
public int visit(IASTExpression expr){
useDefSet(expr, rhs, null, -1);
return PROCESS_SKIP;
}
/**
*
* @param expr The expression being analyzed
* @param side lhs if it is defined, rhs otherwise (rhs)
* @param funcall the function call expression
* @param index the index of the current parameter in funcall
*/
public void useDefSet(IASTExpression expr, int side,
IASTFunctionCallExpression funcall, int index){
// Null expression for empty function parameter
if(expr == null) return;
if(expr instanceof IASTAmbiguousExpression){
}
else if(expr instanceof IASTArraySubscriptExpression){
IASTArraySubscriptExpression asE = (IASTArraySubscriptExpression)expr;
if(side == rhs){
// = a[index_expr]
useDefSet(asE.getArrayExpression(), rhs, funcall, index);
useDefSet(asE.getSubscriptExpression(), rhs, funcall, index);
} else { //lhs
// a[b[i]] = ... , a is defined, b and i are used
useDefSet(asE.getSubscriptExpression(), rhs, funcall, index);
useDefSet(asE.getArrayExpression(), lhs, funcall, index);
}
}
else if(expr instanceof IASTBinaryExpression){
IASTBinaryExpression biE = (IASTBinaryExpression)expr;
int op = biE.getOperator();
if(op == IASTBinaryExpression.op_assign){
// x = y = z is right associative --> x = (y = z)
// So the "side" will be always rhs
useDefSet(biE.getOperand1(), lhs, funcall, index);
useDefSet(biE.getOperand2(), rhs, funcall, index);
}
else if( op == IASTBinaryExpression.op_multiplyAssign ||
op == IASTBinaryExpression.op_divideAssign ||
op == IASTBinaryExpression.op_moduloAssign ||
op == IASTBinaryExpression.op_plusAssign ||
op == IASTBinaryExpression.op_minusAssign ||
op == IASTBinaryExpression.op_shiftLeftAssign ||
op == IASTBinaryExpression.op_shiftRightAssign ||
op == IASTBinaryExpression.op_binaryAndAssign ||
op == IASTBinaryExpression.op_binaryXorAssign ||
op == IASTBinaryExpression.op_binaryOrAssign){
useDefSet(biE.getOperand1(), rhs, funcall, index);
useDefSet(biE.getOperand2(), rhs, funcall, index);
useDefSet(biE.getOperand1(), lhs, funcall, index);
}
else {
useDefSet(biE.getOperand1(), rhs, funcall, index);
useDefSet(biE.getOperand2(), rhs, funcall, index);
}
}
else if(expr instanceof IASTCastExpression){
IASTCastExpression castE = (IASTCastExpression)expr;
useDefSet(castE.getOperand(), side, funcall, index);
}
else if(expr instanceof IASTConditionalExpression){
IASTConditionalExpression condE = (IASTConditionalExpression)expr;
if(side == rhs){
useDefSet(condE.getLogicalConditionExpression(), rhs, funcall, index);
useDefSet(condE.getPositiveResultExpression(), rhs, funcall, index);
useDefSet(condE.getNegativeResultExpression(), rhs, funcall, index);
} else {
// eg. x > y ? x : y = 1
useDefSet(condE.getLogicalConditionExpression(), rhs, funcall, index);
useDefSet(condE.getPositiveResultExpression(), lhs, funcall, index);
useDefSet(condE.getNegativeResultExpression(), lhs, funcall, index);
}
}
else if(expr instanceof IASTExpressionList){
IASTExpressionList exprList = (IASTExpressionList)expr;
IASTExpression[] exprs = exprList.getExpressions();
for(int i = 0; i<exprs.length; i++){
if(funcall != null)
useDefSet(exprs[i], side, funcall, i);
else
useDefSet(exprs[i], side, funcall, index);
}
}
else if(expr instanceof IASTFieldReference){
IASTFieldReference frE = (IASTFieldReference)expr;
useDefSet(frE.getFieldOwner(), side, funcall, index);
}
else if(expr instanceof IASTFunctionCallExpression){
IASTFunctionCallExpression funcE = (IASTFunctionCallExpression)expr;
IASTExpression funcname = funcE.getFunctionNameExpression();
String signature = funcname.getRawSignature();
MPICallGraphNode n = (MPICallGraphNode)cg_.getNode(currentFunc_.getFileName(), signature);
if(n != null){
gdef_ = Util.Union(gdef_, n.getGlobalDef());
guse_ = Util.Union(guse_, n.getGlobalUse());
def_ = Util.Union(def_, n.getGlobalDef());
use_ = Util.Union(use_, n.getGlobalUse());
}
IASTExpression paramE = funcE.getParameterExpression();
if(paramE == null) return;
if(paramE instanceof IASTExpressionList)
useDefSet(funcE.getParameterExpression(), side, funcE, -1);
else
useDefSet(funcE.getParameterExpression(), side, funcE, 0);
}
else if(expr instanceof IASTIdExpression){
IASTIdExpression id = (IASTIdExpression)expr;
IASTName name = id.getName();
String var = name.toString();
if(var.startsWith("MPI_")) return; //$NON-NLS-1$
if(side == rhs){
if(!use_.contains(var))
use_.add(var);
if(cg_.getEnv().contains(var) && !guse_.contains(var))
guse_.add(var);
if(funcall != null){
if(isDefinedParam(funcall, index)){
if(!def_.contains(var))
def_.add(var);
if(cg_.getEnv().contains(var) && !gdef_.contains(var))
gdef_.add(var);
if(isPassableParam(var) && !padef_.contains(var))
padef_.add(var);
}
}
} else { //lhs
if(!def_.contains(var))
def_.add(var);
if(cg_.getEnv().contains(var) && !gdef_.contains(var))
gdef_.add(var);
if(isPassableParam(var) && !padef_.contains(var))
padef_.add(var);
}
}
else if(expr instanceof IASTLiteralExpression){
}
else if(expr instanceof IASTProblemExpression){
}
else if(expr instanceof IASTTypeIdExpression){
}
else if(expr instanceof IASTUnaryExpression){
IASTUnaryExpression uE = (IASTUnaryExpression)expr;
int op = uE.getOperator();
if(op == IASTUnaryExpression.op_prefixIncr ||
op == IASTUnaryExpression.op_prefixDecr ||
op == IASTUnaryExpression.op_postFixIncr ||
op == IASTUnaryExpression.op_postFixDecr) {
useDefSet(uE.getOperand(), rhs, funcall, index);
useDefSet(uE.getOperand(), lhs, funcall, index);
} else {
useDefSet(uE.getOperand(), side, funcall, index);
}
}
else if(expr instanceof ICASTTypeIdInitializerExpression){
}
else{
}
}
private boolean isPassableParam(String name){
IASTFunctionDefinition fdef = currentFunc_.getFuncDef();
IASTFunctionDeclarator fdecl = fdef.getDeclarator();
if(fdecl instanceof IASTStandardFunctionDeclarator){
IASTStandardFunctionDeclarator sfunc = (IASTStandardFunctionDeclarator)fdecl;
IASTParameterDeclaration[] params = sfunc.getParameters();
for(int i = 0; i < params.length; i++){
IASTName param = params[i].getDeclarator().getName();
IASTPointerOperator[] pops = params[i].getDeclarator().getPointerOperators();
if(name.equals(param.toString()) && pops != IASTPointerOperator.EMPTY_ARRAY){
return true;
}
}
} else {
ICASTKnRFunctionDeclarator krfunc = (ICASTKnRFunctionDeclarator)fdecl;
IASTName[] params = krfunc.getParameterNames();
for(int i=0; i<params.length; i++){
if(name.equals(params[i].toString())){
IASTDeclarator decl = krfunc.getDeclaratorForParameterName(params[i]);
if(decl.getPointerOperators() != IASTPointerOperator.EMPTY_ARRAY)
return true;
}
}
}
return false;
}
private boolean isDefinedParam(IASTFunctionCallExpression fE, int index){
if(index == -1) return false;
IASTExpression funcname = fE.getFunctionNameExpression();
String signature = funcname.getRawSignature();
MPICallGraphNode node = (MPICallGraphNode)cg_.getNode(currentFunc_.getFileName(), signature);
if(node != null){
List<String> padef = node.getParamDef();
IASTFunctionDefinition fdef = node.getFuncDef();
IASTFunctionDeclarator fdecl = fdef.getDeclarator();
if(fdecl instanceof IASTStandardFunctionDeclarator){
IASTStandardFunctionDeclarator sfunc = (IASTStandardFunctionDeclarator)fdecl;
IASTParameterDeclaration[] params = sfunc.getParameters();
if(params.length <= index) return false;
IASTName param = params[index].getDeclarator().getName();
if(padef.contains(param.toString())) return true;
} else {
ICASTKnRFunctionDeclarator krfunc = (ICASTKnRFunctionDeclarator)fdecl;
IASTName[] params = krfunc.getParameterNames();
if(params.length <= index) return false;
IASTName param = params[index];
if(padef.contains(param.toString())) return true;
}
} else {
/* Library function calls. Any parameter whose address
* is taken (pointer or array) is both defined and used.
*/
IASTExpression parameterE = fE.getParameterExpression();
if(parameterE instanceof IASTExpressionList){
IASTExpressionList paramEList = (IASTExpressionList)parameterE;
IASTExpression param = (paramEList.getExpressions())[index];
IType type = param.getExpressionType();
if(type instanceof IArrayType ||
type instanceof IPointerType) return true;
}
else{
IType type = parameterE.getExpressionType();
if(type instanceof IArrayType ||
type instanceof IPointerType) return true;
}
}
return false;
}
/**
* All parameters of a function and used globals are assumed to be
* defined at the entry block.
*/
private void setEntryBlock(MPIBlock entry){
List<String> def = new ArrayList<String>();
IASTFunctionDefinition fdef = currentFunc_.getFuncDef();
IASTFunctionDeclarator fdecl = fdef.getDeclarator();
if(fdecl instanceof IASTStandardFunctionDeclarator){
IASTStandardFunctionDeclarator sfunc = (IASTStandardFunctionDeclarator)fdecl;
IASTParameterDeclaration[] params = sfunc.getParameters();
for(int i=0; i<params.length; i++){
IASTName param = params[i].getDeclarator().getName();
def.add(param.toString());
}
} else {
ICASTKnRFunctionDeclarator krfunc = (ICASTKnRFunctionDeclarator)fdecl;
IASTName[] params = krfunc.getParameterNames();
for(int i=0; i<params.length; i++){
IASTName param = params[i];
def.add(param.toString());
}
}
for(Iterator<String> i = currentFunc_.getGlobalUse().iterator(); i.hasNext();){
def.add(i.next());
}
entry.setDef(def);
entry.setUse(new ArrayList<String>());
}
/**
* All defined global variables and defined passable parameters are assumed
* to be used in the exit block
*/
private void setExitBlock(MPIBlock exit){
List<String> use = new ArrayList<String>();
for(Iterator<String> i = currentFunc_.getGlobalDef().iterator(); i.hasNext();){
use.add(i.next());
}
for(Iterator<String> i = currentFunc_.getParamDef().iterator(); i.hasNext();){
use.add(i.next());
}
exit.setUse(use);
exit.setDef(new ArrayList<String>());
}
}