blob: 9f6ba8e5dcb6e0c265737f91fb01ecbf7177047c [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.Enumeration;
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.gnu.c.ICASTKnRFunctionDeclarator;
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;
public class MPISingleAssignAnalysis {
protected ICallGraph cg_;
protected IControlFlowGraph cfg_;
protected MPICallGraphNode currentNode_;
protected Hashtable<String,Integer> assignNum_;
protected Hashtable<String,Boolean> type_;
private static final boolean traceOn=false;
public MPISingleAssignAnalysis(ICallGraph cg){
cg_ = cg;
}
public void run(){
for(ICallGraphNode n = cg_.botEntry(); n != null; n = n.botNext()){
MPICallGraphNode currentNode_ = (MPICallGraphNode)n;
if(traceOn)System.out.println(currentNode_.getFuncName());
cfg_ = currentNode_.getCFG();
assignNum_ = currentNode_.getSAVar();
type_ = currentNode_.getSAVarPointer();
dataCollector dc = new dataCollector();
dc.run();
SingleAssignAnalyzer saa = new SingleAssignAnalyzer();
saa.run();
for(Enumeration<String> e = currentNode_.getSAVar().keys(); e.hasMoreElements();){
String var = e.nextElement();
if(traceOn)System.out.println(var + " is defined " + currentNode_.getSAVar().get(var).intValue() + " times"); //$NON-NLS-1$ //$NON-NLS-2$
}
}
}
class dataCollector extends ASTVisitor{
public void run(){
this.shouldVisitStatements = true;
this.shouldVisitDeclarations = true;
/* global variables */
for(int i=0; i<cg_.getEnv().size(); i++){
String var = cg_.getEnv().get(i);
assignNum_.put(var, new Integer(0));
type_.put(var, ((MPICallGraph)cg_).getGVPointer().get(i));
}
/* function parameters */
List<String> parameters = new ArrayList<String>();
List<Boolean> pointers = new ArrayList<Boolean>();
getParameters(currentNode_.getFuncDef(), parameters, pointers);
for(int i=0; i<parameters.size(); i++){
String var = parameters.get(i);
assignNum_.put(var, new Integer(0));
type_.put(var, pointers.get(i));
}
/* local variables */
currentNode_.getFuncDef().accept(this);
}
protected void getParameters(IASTFunctionDefinition fd,
List<String> paramList, List<Boolean> pointerList){
IASTFunctionDeclarator fdecl = fd.getDeclarator();
if(fdecl instanceof IASTStandardFunctionDeclarator){
IASTStandardFunctionDeclarator sfunc = (IASTStandardFunctionDeclarator)fdecl;
IASTParameterDeclaration[] params = sfunc.getParameters();
for(int i=0; i<params.length; i++){
paramList.add(params[i].getDeclarator().getName().toString());
IASTPointerOperator[] pops = params[i].getDeclarator().getPointerOperators();
if(pops != IASTPointerOperator.EMPTY_ARRAY)
pointerList.add(new Boolean(true));
else
pointerList.add(new Boolean(false));
}
} else {
ICASTKnRFunctionDeclarator krfunc = (ICASTKnRFunctionDeclarator)fdecl;
IASTName[] params = krfunc.getParameterNames();
for(int i=0; i<params.length; i++){
paramList.add(params[i].toString());
IASTDeclarator decl = krfunc.getDeclaratorForParameterName(params[i]);
if(decl.getPointerOperators() != IASTPointerOperator.EMPTY_ARRAY)
pointerList.add(new Boolean(true));
else
pointerList.add(new Boolean(false));
}
}
}
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++){
String var = declarators[i].getName().toString();
assignNum_.put(var, new Integer(0));
if(declarators[i].getPointerOperators() != IASTPointerOperator.EMPTY_ARRAY)
type_.put(var, new Boolean(true));
else
type_.put(var, new Boolean(false));
}
}
return PROCESS_SKIP;
}
return PROCESS_CONTINUE;
}
}
class SingleAssignAnalyzer extends ASTVisitor{
public void run(){
this.shouldVisitDeclarations = true;
this.shouldVisitExpressions = true;
this.shouldVisitStatements = true;
}
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){
processInitializer(init, name.toString());
}
}
}
return PROCESS_SKIP;
}
return PROCESS_CONTINUE;
}
protected void processInitializer(IASTInitializer init, String var){
if(init != null){
if(init instanceof IASTInitializerExpression){
IASTInitializerExpression initE = (IASTInitializerExpression)init;
IASTExpression e = initE.getExpression();
List<String> def = new ArrayList<String>();
List<String> use = new ArrayList<String>();
List<String> ldf = new ArrayList<String>();
List<String> rdf = new ArrayList<String>();
boolean value = saExpr(e, rhs, null, -1, def, use, ldf, rdf);
for(Iterator<String> i = use.iterator(); i.hasNext();){
String v = i.next();
int num = assignNum_.get(v).intValue();
boolean pointerType = type_.get(v).booleanValue();
if(pointerType) //pointers are used for math operations
assignNum_.put(v, new Integer(num + 2));
}
boolean pointerType = type_.get(var).booleanValue();
if(pointerType){
if(value) // init by malloc
assignNum_.put(var, new Integer(1));
else
assignNum_.put(var, new Integer(2));
} else {
assignNum_.put(var, new Integer(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], var);
}
}
else if(init instanceof ICASTDesignatedInitializer){
System.out.println("ICASTDesignatedInitializer found !"); //$NON-NLS-1$
}
}
}
public int visit(IASTExpression expr){
saExpr(expr, rhs, null, -1, new ArrayList<String>(),
new ArrayList<String>(), new ArrayList<String>(),
new ArrayList<String>());
return PROCESS_SKIP;
}
protected final int lhs = 0;
protected final int rhs = 1;
protected final int lderef = 2; //lhs and dereference
protected final int rderef = 3; //rhs and dereference
/** return: is a malloc(calloc, realloc) met? <br>
* Params: def -- the set of defined variables <br>
* use -- the set of used (other than de-referenced) variables <br>
* ref -- the set of de-referenced variables
*/
protected boolean saExpr(IASTExpression expr, int side,
IASTFunctionCallExpression func, int index,
List<String> def, List<String> use,
List<String> ldf, List<String> rdf){
List<String> d1 = new ArrayList<String>();
List<String> d2 = new ArrayList<String>();
List<String> d3 = new ArrayList<String>();
List<String> u1 = new ArrayList<String>();
List<String> u2 = new ArrayList<String>();
List<String> u3 = new ArrayList<String>();
List<String> lr1 = new ArrayList<String>();
List<String> lr2 = new ArrayList<String>();
List<String> lr3 = new ArrayList<String>();
List<String> rr1 = new ArrayList<String>();
List<String> rr2 = new ArrayList<String>();
List<String> rr3 = new ArrayList<String>();
boolean v1 = false, v2 = false, v3 = false;
if(expr == null) return false;
if(expr instanceof IASTArraySubscriptExpression){
IASTArraySubscriptExpression asE = (IASTArraySubscriptExpression)expr;
if(side == rhs || side == rderef){
v1 = saExpr(asE.getArrayExpression(), rderef, func, index, d1, u1, lr1, rr1);
v2 = saExpr(asE.getSubscriptExpression(), rhs, func, index, d2, u2, lr2, rr2);
} else {
v1 = saExpr(asE.getArrayExpression(), lderef, func, index, d1, u1, lr1, rr1);
v2 = saExpr(asE.getSubscriptExpression(), rhs, func, index, d2, u2, lr2, rr2);
}
Util.addAll(def, d1);
Util.addAll(def, d2);
Util.addAll(use, u1);
Util.addAll(use, u2);
Util.addAll(ldf, lr1);
Util.addAll(ldf, lr2);
Util.addAll(rdf, rr1);
Util.addAll(rdf, rr2);
return v1 | v2;
}
else if(expr instanceof IASTBinaryExpression){
IASTBinaryExpression biE = (IASTBinaryExpression)expr;
int op = biE.getOperator();
if(op == IASTBinaryExpression.op_assign){
v1 = saExpr(biE.getOperand1(), lhs, func, index, d1, u1, lr1, rr1);
v2 = saExpr(biE.getOperand2(), rhs, func, index, d2, u2, lr2, rr2);
for(Iterator<String> i = d1.iterator(); i.hasNext();){
String var = i.next();
int num = assignNum_.get(var).intValue();
boolean pointerType = type_.get(var).booleanValue();
if(pointerType){
if(v2) // init by malloc
assignNum_.put(var, new Integer(num + 1));
else
assignNum_.put(var, new Integer(num + 2));
} else {
assignNum_.put(var, new Integer(num + 1));
}
}
for(Iterator<String> i = u1.iterator(); i.hasNext();){
String var = i.next();
int num = assignNum_.get(var).intValue();
boolean pointerType = type_.get(var).booleanValue();
if(pointerType) //pointers are used for math operations
assignNum_.put(var, new Integer(num + 2));
}
for(Iterator<String> i = u2.iterator(); i.hasNext();){
String var = i.next();
int num = assignNum_.get(var).intValue();
boolean pointerType = type_.get(var).booleanValue();
if(pointerType) //pointers are used for math operations
assignNum_.put(var, new Integer(num + 2));
}
}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){
v1 = saExpr(biE.getOperand1(), lhs, func, index, d1, u1, lr1, rr1);
v2 = saExpr(biE.getOperand1(), rhs, func, index, d2, u2, lr2, rr2);
v3 = saExpr(biE.getOperand2(), rhs, func, index, d3, u3, lr2, rr3);
for(Iterator<String> i = d1.iterator(); i.hasNext();){
String var = i.next();
int num = assignNum_.get(var).intValue();
boolean pointerType = type_.get(var).booleanValue();
if(pointerType){
if(v2) // init by malloc
assignNum_.put(var, new Integer(num + 1));
else
assignNum_.put(var, new Integer(num + 2));
} else {
assignNum_.put(var, new Integer(num + 1));
}
}
for(Iterator<String> i = u2.iterator(); i.hasNext();){
String var = i.next();
int num = assignNum_.get(var).intValue();
boolean pointerType = type_.get(index).booleanValue();
if(pointerType) //pointers are used for math operations
assignNum_.put(var, new Integer(num + 2));
}
for(Iterator<String> i = u3.iterator(); i.hasNext();){
String var = i.next();
int num = assignNum_.get(var).intValue();
boolean pointerType = type_.get(index).booleanValue();
if(pointerType) //pointers are used for math operations
assignNum_.put(var, new Integer(num + 2));
}
} else {
v1 = saExpr(biE.getOperand1(), rhs, func, index, d1, u1, lr1, rr1);
v2 = saExpr(biE.getOperand2(), rhs, func, index, d2, u2, lr2, rr2);
}
Util.addAll(def, d1);
Util.addAll(def, d2);
Util.addAll(def, d3);
Util.addAll(use, u1);
Util.addAll(use, u2);
Util.addAll(use, u3);
Util.addAll(ldf, lr1);
Util.addAll(ldf, lr2);
Util.addAll(ldf, lr3);
Util.addAll(rdf, rr1);
Util.addAll(rdf, rr2);
Util.addAll(rdf, rr3);
return v1 | v2 | v3;
}
else if(expr instanceof IASTCastExpression){
IASTCastExpression castE = (IASTCastExpression)expr;
v1 = saExpr(castE.getOperand(), side, func, index, d1, u1, lr1, rr1);
Util.addAll(def, d1);
Util.addAll(use, u1);
Util.addAll(ldf, lr1);
Util.addAll(rdf, rr1);
return v1;
}
else if(expr instanceof IASTConditionalExpression){
IASTConditionalExpression condE = (IASTConditionalExpression)expr;
if(side == rhs || side == rderef){
v1 = saExpr(condE.getLogicalConditionExpression(), side, func, index, d1, u1, lr1, rr1);
v2 = saExpr(condE.getPositiveResultExpression(), side, func, index, d2, u2, lr2, rr2);
v3 = saExpr(condE.getNegativeResultExpression(), side, func, index, d3, u3, lr3, rr3);
} else {
// eg. x > y ? x : y = 1
if(side == lhs)
v1 = saExpr(condE.getLogicalConditionExpression(), rhs, func, index, d1, u1, lr1, rr1);
else // side = lderef
v1 = saExpr(condE.getLogicalConditionExpression(), rderef, func, index, d1, u1, lr1, rr1);
v2 = saExpr(condE.getPositiveResultExpression(), side, func, index, d2, u2, lr2, rr2);
v3 = saExpr(condE.getNegativeResultExpression(), side, func, index, d3, u3, lr3, rr3);
}
Util.addAll(def, d1);
Util.addAll(def, d2);
Util.addAll(def, d3);
Util.addAll(use, u1);
Util.addAll(use, u2);
Util.addAll(use, u3);
Util.addAll(ldf, lr1);
Util.addAll(ldf, lr2);
Util.addAll(ldf, lr3);
Util.addAll(rdf, rr1);
Util.addAll(rdf, rr2);
Util.addAll(rdf, rr3);
return v1 | v2 | v3;
}
else if(expr instanceof IASTExpressionList){
IASTExpressionList exprList = (IASTExpressionList)expr;
IASTExpression[] exprs = exprList.getExpressions();
for(int i = 0; i<exprs.length; i++){
if(func != null)
v1 = v1 | saExpr(exprs[i], side, func, i, d1, u1, lr1, rr1);
else
v1 = v1 | saExpr(exprs[i], side, func, index, d1, u1, lr1, rr1);
Util.addAll(def, d1);
Util.addAll(use, u1);
Util.addAll(ldf, lr1);
Util.addAll(rdf, rr1);
}
return v1;
}
else if(expr instanceof IASTFieldReference){
IASTFieldReference frE = (IASTFieldReference)expr;
if(side == lhs || side == lderef)
v1 = saExpr(frE.getFieldOwner(), lderef, func, index, d1, u1, lr1, rr1);
else
v1 = saExpr(frE.getFieldOwner(), rderef, func, index, d1, u1, lr1, rr1);
Util.addAll(def, d1);
Util.addAll(use, u1);
Util.addAll(ldf, lr1);
Util.addAll(rdf, rr1);
return v1;
}
else if(expr instanceof IASTFunctionCallExpression){
IASTFunctionCallExpression funcE = (IASTFunctionCallExpression)expr;
IASTExpression funcname = funcE.getFunctionNameExpression();
String signature = funcname.getRawSignature();
if(signature.equals("malloc") || signature.equals("calloc") || //$NON-NLS-1$ //$NON-NLS-2$
signature.equals("realloc")) //$NON-NLS-1$
return true;
IASTExpression paramE = funcE.getParameterExpression();
if(paramE == null) return false;
if(paramE instanceof IASTExpressionList)
v1 = saExpr(paramE, side, funcE, -1, d1, u1, lr1, rr1);
else
v1 = saExpr(paramE, side, funcE, 0, d1, u1, lr1, rr1);
/* update assignment number of global var */
MPICallGraphNode node = (MPICallGraphNode)cg_.getNode(currentNode_.getFileName(), signature);
if(node != null){
for(Iterator<String> i=cg_.getEnv().iterator(); i.hasNext();){
String gvar = i.next();
if(!u1.contains(gvar) && !rr1.contains(gvar)){
int fnum = node.getSAVar().get(gvar).intValue();
int num = assignNum_.get(gvar).intValue();
assignNum_.put(gvar, new Integer(fnum + num));
}
}
}
Util.addAll(def, d1);
Util.addAll(use, u1);
Util.addAll(ldf, lr1);
Util.addAll(rdf, rr1);
return v1;
}
else if(expr instanceof IASTIdExpression){
IASTIdExpression id = (IASTIdExpression)expr;
IASTName name = id.getName();
String var = name.toString();
if(var.startsWith("MPI_")) return false; //$NON-NLS-1$
int fnum = 0;
if(func != null){
fnum = getParamAssignNum(func, index);
}
if(side == rhs){
if(!use.contains(var))
use.add(var);
int num = assignNum_.get(var).intValue();
assignNum_.put(var, new Integer(num + fnum));
} else if(side == lhs){
if(!def.contains(var))
def.add(var);
} else if(side == lderef){
if(!ldf.contains(var))
ldf.add(var);
} else { //rderef
if(!rdf.contains(var))
rdf.add(var);
int num = assignNum_.get(var).intValue();
assignNum_.put(var, new Integer(num + fnum));
}
return false;
}
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) {
v1 = saExpr(uE.getOperand(), rhs, func, index, d1, u1, lr1, rr1);
v2 = saExpr(uE.getOperand(), lhs, func, index, d2, u2, lr2, rr2);
for(Iterator<String> i = d1.iterator(); i.hasNext();){
String var = i.next();
int num = assignNum_.get(var).intValue();
boolean pointerType = type_.get(var).booleanValue();
if(pointerType){
if(v2) // init by malloc
assignNum_.put(var, new Integer(num + 1));
else
assignNum_.put(var, new Integer(num + 2));
} else {
assignNum_.put(var, new Integer(num + 1));
}
}
for(Iterator<String> i = u1.iterator(); i.hasNext();){
String var = i.next();
int num = assignNum_.get(var).intValue();
boolean pointerType = type_.get(var).booleanValue();
if(pointerType) //pointers are used for math operations
assignNum_.put(var, new Integer(num + 2));
}
for(Iterator<String> i = u2.iterator(); i.hasNext();){
String var = i.next();
int num = assignNum_.get(var).intValue();
boolean pointerType = type_.get(var).booleanValue();
if(pointerType) //pointers are used for math operations
assignNum_.put(var, new Integer(num + 2));
}
Util.addAll(def, d1);
Util.addAll(def, d2);
Util.addAll(use, u1);
Util.addAll(use, u2);
Util.addAll(ldf, lr1);
Util.addAll(ldf, lr2);
Util.addAll(rdf, rr1);
Util.addAll(rdf, rr2);
} else {
v1 = saExpr(uE.getOperand(), side, func, index, d1, u1, lr1, rr1);
Util.addAll(def, d1);
Util.addAll(use, u1);
Util.addAll(ldf, lr1);
Util.addAll(rdf, rr1);
}
return v1 | v2;
}
return false;
}
protected int getParamAssignNum(IASTFunctionCallExpression fE, int index){
if(index == -1) return 0;
IASTExpression funcname = fE.getFunctionNameExpression();
String signature = funcname.getRawSignature();
MPICallGraphNode node = (MPICallGraphNode)cg_.getNode(currentNode_.getFileName(), signature);
if(node != null){
Hashtable<String,Integer> funcAssignNum = node.getSAVar();
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 0;
IASTName param = params[index].getDeclarator().getName();
return funcAssignNum.get(param.toString()).intValue();
} else {
ICASTKnRFunctionDeclarator krfunc = (ICASTKnRFunctionDeclarator)fdecl;
IASTName[] params = krfunc.getParameterNames();
if(params.length <= index) return 0;
IASTName param = params[index];
return funcAssignNum.get(param.toString()).intValue();
}
} 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 2;
}
else{
IType type = parameterE.getExpressionType();
if(type instanceof IArrayType ||
type instanceof IPointerType) return 2;
}
}
return 0;
}
}
}