blob: 654e15004e9b2f9ab9ae4290596e24f355d99f9f [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.LinkedList;
import java.util.ListIterator;
import org.eclipse.cdt.core.dom.ast.ASTVisitor;
import org.eclipse.cdt.core.dom.ast.IASTBinaryExpression;
import org.eclipse.cdt.core.dom.ast.IASTBreakStatement;
import org.eclipse.cdt.core.dom.ast.IASTCaseStatement;
import org.eclipse.cdt.core.dom.ast.IASTCompoundStatement;
import org.eclipse.cdt.core.dom.ast.IASTDeclSpecifier;
import org.eclipse.cdt.core.dom.ast.IASTDeclarationStatement;
import org.eclipse.cdt.core.dom.ast.IASTDeclarator;
import org.eclipse.cdt.core.dom.ast.IASTDoStatement;
import org.eclipse.cdt.core.dom.ast.IASTExpression;
import org.eclipse.cdt.core.dom.ast.IASTExpressionStatement;
import org.eclipse.cdt.core.dom.ast.IASTForStatement;
import org.eclipse.cdt.core.dom.ast.IASTFunctionDefinition;
import org.eclipse.cdt.core.dom.ast.IASTGotoStatement;
import org.eclipse.cdt.core.dom.ast.IASTIdExpression;
import org.eclipse.cdt.core.dom.ast.IASTIfStatement;
import org.eclipse.cdt.core.dom.ast.IASTInitializerExpression;
import org.eclipse.cdt.core.dom.ast.IASTLabelStatement;
import org.eclipse.cdt.core.dom.ast.IASTLiteralExpression;
import org.eclipse.cdt.core.dom.ast.IASTName;
import org.eclipse.cdt.core.dom.ast.IASTNode;
import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclSpecifier;
import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclaration;
import org.eclipse.cdt.core.dom.ast.IASTStatement;
import org.eclipse.cdt.core.dom.ast.IASTSwitchStatement;
import org.eclipse.cdt.core.dom.ast.IASTUnaryExpression;
import org.eclipse.cdt.core.dom.ast.IASTWhileStatement;
import org.eclipse.cdt.internal.core.dom.parser.c.CASTBinaryExpression;
import org.eclipse.cdt.internal.core.dom.parser.c.CASTBreakStatement;
import org.eclipse.cdt.internal.core.dom.parser.c.CASTCompoundStatement;
import org.eclipse.cdt.internal.core.dom.parser.c.CASTDeclarationStatement;
import org.eclipse.cdt.internal.core.dom.parser.c.CASTDoStatement;
import org.eclipse.cdt.internal.core.dom.parser.c.CASTExpressionStatement;
import org.eclipse.cdt.internal.core.dom.parser.c.CASTForStatement;
import org.eclipse.cdt.internal.core.dom.parser.c.CASTIdExpression;
import org.eclipse.cdt.internal.core.dom.parser.c.CASTIfStatement;
import org.eclipse.cdt.internal.core.dom.parser.c.CASTInitializerExpression;
import org.eclipse.cdt.internal.core.dom.parser.c.CASTLiteralExpression;
import org.eclipse.cdt.internal.core.dom.parser.c.CASTName;
import org.eclipse.cdt.internal.core.dom.parser.c.CASTSimpleDeclSpecifier;
import org.eclipse.cdt.internal.core.dom.parser.c.CASTSimpleDeclaration;
import org.eclipse.cdt.internal.core.dom.parser.c.CASTSwitchStatement;
import org.eclipse.cdt.internal.core.dom.parser.c.CASTUnaryExpression;
import org.eclipse.cdt.internal.core.dom.parser.c.CASTWhileStatement;
import org.eclipse.ptp.pldt.mpi.analysis.cdt.graphs.ICallGraph;
import org.eclipse.ptp.pldt.mpi.analysis.cdt.graphs.ICallGraphNode;
public class GotoEliminator{
private ICallGraph cg_;
private LinkedList gotoList_;
private LinkedList labelList_;
private ICallGraphNode currentNode_;
private int switch_count = 0;
public GotoEliminator(ICallGraph cg){
cg_ = cg;
gotoList_ = null;
labelList_ = null;
currentNode_ = null;
}
public void run(){
for(ICallGraphNode node = cg_.botEntry(); node != null; node = node.botNext()){
currentNode_ = node;
normalizeCompoundStmt(node.getFuncDef().getBody());
GotoLabelCollector glc = new GotoLabelCollector(node);
gotoList_ = glc.getGotoList();
labelList_ = glc.getLabelList();
if(gotoList_.size() == 0) continue;
gotoPreprocessing();
labelPreprocessing();
while(gotoList_.size() > 0){
IASTGotoStatement gotoS = (IASTGotoStatement)gotoList_.remove();
IASTLabelStatement label = findLabel(gotoS);
if(label == null){
System.out.println("Empty goto label!"); //$NON-NLS-1$
continue;
}
while(!isDirectedRelated(gotoS, label) && !isSibling(gotoS, label)){
moveOutward(gotoS);
}
if(isDirectedRelated(gotoS, label)){
if(Level(gotoS) > Level(label)){
while(Level(gotoS) > Level(label))
moveOutward(gotoS);
}
else{
while(!Offset(gotoS, label))
lifting(gotoS);
while(Level(gotoS) < Level(label))
moveInward(gotoS);
}
}
eliminatingGoto(gotoS);
}
while(labelList_.size() > 0){
IASTLabelStatement label = (IASTLabelStatement)labelList_.remove();
eliminatingStatement(label);
}
}
}
private void labelPreprocessing(){
for(ListIterator li = labelList_.listIterator(); li.hasNext();){
IASTLabelStatement label = (IASTLabelStatement)li.next();
IASTName labelname = label.getName();
String labelvar = "goto_" + labelname.toString(); //$NON-NLS-1$
createDeclaration(labelvar);
setLabelVariable(labelvar, label);
}
}
private void gotoPreprocessing(){
for(ListIterator li = gotoList_.listIterator(); li.hasNext();){
IASTGotoStatement gotoS = (IASTGotoStatement)li.next();
if(!(gotoS.getParent() instanceof IASTIfStatement)){
IASTLiteralExpression condE = new CASTLiteralExpression();
condE.setValue("true"); //$NON-NLS-1$
IASTIfStatement ifS = new CASTIfStatement();
ifS.setConditionExpression(condE);
condE.setParent(ifS);
ifS.setThenClause(gotoS);
ifS.setElseClause(null);
gotoS.setParent(ifS);
replaceStatement(gotoS, ifS);
}
}
}
private void createDeclaration(String var){
IASTSimpleDeclaration decl = new CASTSimpleDeclaration();
IASTSimpleDeclSpecifier declSpec = new CASTSimpleDeclSpecifier();
declSpec.setConst(false);
declSpec.setVolatile(false);
declSpec.setInline(false);
declSpec.setStorageClass(IASTDeclSpecifier.sc_unspecified);
declSpec.setType(IASTSimpleDeclSpecifier.t_int);
declSpec.setLong(false);
declSpec.setUnsigned(false);
declSpec.setSigned(true);
declSpec.setShort(false);
decl.setDeclSpecifier(declSpec);
declSpec.setParent(decl);
declSpec.setPropertyInParent(IASTSimpleDeclaration.DECL_SPECIFIER);
IASTDeclarator [] declarators = new IASTDeclarator[1];
IASTName name = new CASTName(var.toCharArray());
declarators[0].setName(name);
IASTLiteralExpression init = new CASTLiteralExpression();
init.setValue("0"); //$NON-NLS-1$
IASTInitializerExpression initE = new CASTInitializerExpression();
initE.setExpression(init);
declarators[0].setInitializer(initE);
decl.addDeclarator(declarators[0]);
declarators[0].setParent(decl);
declarators[0].setPropertyInParent(IASTSimpleDeclaration.DECLARATOR);
IASTDeclarationStatement declStmt = new CASTDeclarationStatement();
declStmt.setDeclaration(decl);
IASTCompoundStatement body = (IASTCompoundStatement)currentNode_.getFuncDef().getBody();
IASTStatement[] stmts = body.getStatements();
body.addStatement(stmts[stmts.length-1]);
for(int i=stmts.length-1; i>0; i--){
stmts[i] = stmts[i-1];
}
stmts[0] = declStmt;
stmts[0].setParent(stmts[1].getParent());
stmts[0].setPropertyInParent(stmts[1].getPropertyInParent());
}
private void setLabelVariable(String var, IASTLabelStatement label){
IASTName name = new CASTName(var.toCharArray());
IASTIdExpression id = new CASTIdExpression();
id.setName(name);
name.setParent(id);
IASTLiteralExpression value = new CASTLiteralExpression();
value.setValue("0"); //$NON-NLS-1$
IASTBinaryExpression biE = new CASTBinaryExpression();
biE.setOperand1(id);
biE.setOperand2(value);
id.setParent(biE);
value.setParent(biE);
biE.setOperator(IASTBinaryExpression.op_assign);
IASTExpressionStatement exprStmt = new CASTExpressionStatement();
exprStmt.setExpression(biE);
biE.setParent(exprStmt);
IASTCompoundStatement compStmt = new CASTCompoundStatement();
if(label.getNestedStatement() != null){
IASTStatement nestedStmt = label.getNestedStatement();
compStmt.setParent(nestedStmt.getParent());
compStmt.setPropertyInParent(nestedStmt.getPropertyInParent());
compStmt.addStatement(exprStmt);
compStmt.addStatement(nestedStmt);
}
else {
compStmt.addStatement(exprStmt);
compStmt.setParent(label);
}
label.setNestedStatement(compStmt);
}
private IASTLabelStatement findLabel(IASTGotoStatement gotoS){
IASTName labelname = gotoS.getName();
for(ListIterator li = labelList_.listIterator(); li.hasNext();){
IASTLabelStatement s = (IASTLabelStatement)li.next();
if(s.getName().toString().equals(labelname.toString()))
return s;
}
return null;
}
private boolean isSibling(IASTNode s1, IASTNode s2){
IASTNode p1 = s1.getParent();
IASTNode p2 = s2.getParent();
if(p1 == p2 && p1 instanceof IASTCompoundStatement)
return true;
else
return false;
}
private boolean isDirectedRelated(IASTGotoStatement gotoS,
IASTLabelStatement labelS){
IASTNode parent;
parent = gotoS.getParent();
while(!(parent instanceof IASTFunctionDefinition)){
if(isSibling(labelS, parent)) return true;
else parent = parent.getParent();
}
parent = labelS.getParent();
while(!(parent instanceof IASTFunctionDefinition)){
if(isSibling(gotoS, parent)) return true;
else parent = parent.getParent();
}
return false;
}
/* Delete redundantly nested compoundStatement
* e.g. {{{s}}} --> {s}
* e.g. {{s1}{s2}} --> {s1 s2}
*/
private void normalizeCompoundStmt(IASTStatement stmt){
if(stmt instanceof IASTCompoundStatement){
IASTCompoundStatement newCompS = new CASTCompoundStatement();
IASTStatement stmts[] = ((IASTCompoundStatement)stmt).getStatements();
for(int i = 0; i<stmts.length; i++){
normalizeCompoundStmt(stmts[i]);
if(stmts[i] instanceof IASTCompoundStatement){
IASTCompoundStatement subCompS = (IASTCompoundStatement)stmts[i];
IASTStatement subStmts[] = subCompS.getStatements();
for(int j=0; j<subStmts.length; j++){
newCompS.addStatement(subStmts[j]);
subStmts[j].setParent(newCompS); // TODO: check here
}
} else {
newCompS.addStatement(stmts[i]);
stmts[i].setParent(newCompS); // TODO: check here
}
}
replaceStatement(stmt, newCompS);
}
else if(stmt instanceof IASTDoStatement){
normalizeCompoundStmt(((IASTDoStatement)stmt).getBody());
}
else if(stmt instanceof IASTForStatement){
normalizeCompoundStmt(((IASTForStatement)stmt).getBody());
}
else if(stmt instanceof IASTIfStatement){
normalizeCompoundStmt(((IASTIfStatement)stmt).getThenClause());
normalizeCompoundStmt(((IASTIfStatement)stmt).getElseClause());
}
else if(stmt instanceof IASTSwitchStatement){
normalizeCompoundStmt(((IASTSwitchStatement)stmt).getBody());
}
else if(stmt instanceof IASTWhileStatement){
normalizeCompoundStmt(((IASTWhileStatement)stmt).getBody());
}
}
/* TODO: check the order of replace and parent setting */
private void moveOutward(IASTGotoStatement gotoS){
String labelname = "goto_" + gotoS.getName().toString(); //$NON-NLS-1$
IASTNode parent = gotoS.getParent().getParent();
IASTNode body = gotoS.getParent();
IASTIfStatement gotoIfStmt = (IASTIfStatement)body;
while(!(parent instanceof IASTFunctionDefinition)){
if(parent instanceof IASTDoStatement ||
parent instanceof IASTForStatement ||
parent instanceof IASTWhileStatement ||
parent instanceof IASTSwitchStatement){
IASTCompoundStatement newbody = new CASTCompoundStatement();
if(body instanceof IASTCompoundStatement){
IASTStatement[] stmts = ((IASTCompoundStatement)body).getStatements();
int index;
for(index=0; index<stmts.length; index++){
if(stmts[index] == gotoIfStmt) break;
}
for(int j=0; j<index; j++){
newbody.addStatement(stmts[j]);
}
IASTStatement assignS = makeGotoIfCondStoreStmt(gotoIfStmt.getConditionExpression(), labelname);
newbody.addStatement(assignS);
IASTName condname = new CASTName(labelname.toCharArray());
IASTIdExpression condE = new CASTIdExpression();
condE.setName(condname);
condname.setParent(condE);
IASTIfStatement ifS = new CASTIfStatement();
ifS.setConditionExpression(condE);
IASTBreakStatement breakS = new CASTBreakStatement();
ifS.setThenClause(breakS);
ifS.setElseClause(null);
condE.setParent(ifS);
breakS.setParent(ifS);
newbody.addStatement(ifS);
for(int j=index+1; j<stmts.length; j++){
newbody.addStatement(stmts[j]);
}
}
else if(body == gotoIfStmt){
IASTStatement assignS = makeGotoIfCondStoreStmt(gotoIfStmt.getConditionExpression(), labelname);
newbody.addStatement(assignS);
IASTName condname = new CASTName(labelname.toCharArray());
IASTIdExpression condE = new CASTIdExpression();
condE.setName(condname);
condname.setParent(condE);
IASTIfStatement ifS = new CASTIfStatement();
ifS.setConditionExpression(condE);
IASTBreakStatement breakS = new CASTBreakStatement();
ifS.setThenClause(breakS);
ifS.setElseClause(null);
condE.setParent(ifS);
breakS.setParent(ifS);
newbody.addStatement(ifS);
}
if(parent instanceof IASTDoStatement){
((CASTDoStatement)parent).replace(body, newbody);
} else if(parent instanceof IASTForStatement){
((CASTForStatement)parent).replace(body, newbody);
} else if(parent instanceof IASTWhileStatement){
((CASTWhileStatement)parent).replace(body, newbody);
} else if(parent instanceof IASTSwitchStatement){
((CASTSwitchStatement)parent).replace(body, newbody);
}
IASTStatement newIfStmt = makeNewGotoIfStmt(labelname, gotoS);
appendStatement(newIfStmt, (IASTStatement)parent);
break;
}
else if(parent instanceof IASTIfStatement){
if(body instanceof IASTCompoundStatement){
IASTStatement[] stmts = ((IASTCompoundStatement)body).getStatements();
int index;
for(index=0; index<stmts.length; index++){
if(stmts[index] == gotoIfStmt) break;
}
IASTCompoundStatement newbody = new CASTCompoundStatement();
for(int j=0; j<index; j++){
newbody.addStatement(stmts[j]);
}
IASTStatement assignS = makeGotoIfCondStoreStmt(gotoIfStmt.getConditionExpression(), labelname);
newbody.addStatement(assignS);
if(index < stmts.length-1){ //some statements after the goto
IASTCompoundStatement ifbody = new CASTCompoundStatement();
for(int j = index+1; j<stmts.length; j++){
ifbody.addStatement(stmts[j]);
}
IASTName condname = new CASTName(labelname.toCharArray());
IASTIdExpression condid = new CASTIdExpression();
condid.setName(condname);
condname.setParent(condid);
IASTUnaryExpression condE = new CASTUnaryExpression();
condE.setOperand(condid);
condE.setOperator(IASTUnaryExpression.op_not);
condid.setParent(condE);
IASTIfStatement ifStmt = new CASTIfStatement();
ifStmt.setConditionExpression(condE);
ifStmt.setThenClause(ifbody);
ifStmt.setElseClause(null);
condE.setParent(ifStmt);
ifbody.setParent(ifStmt);
newbody.addStatement(ifStmt);
}
((CASTIfStatement)parent).replace(body, newbody);
}
else if(body == gotoIfStmt){
IASTStatement assignS = makeGotoIfCondStoreStmt(gotoIfStmt.getConditionExpression(), labelname);
((CASTIfStatement)parent).replace(gotoIfStmt, assignS);
}
IASTStatement newifStmt = makeNewGotoIfStmt(labelname, gotoS);
appendStatement(newifStmt, (IASTStatement)parent);
break;
}
else {
body = parent;
parent = body.getParent();
}
}
}
private void moveInward(IASTGotoStatement gotoS){
IASTIfStatement gotoIfStmt = (IASTIfStatement)gotoS.getParent();
String labelname = "goto_" + gotoS.getName().toString(); //$NON-NLS-1$
IASTLabelStatement label = findLabel(gotoS);
IASTStatement enclosingStmt = null;
IASTStatement clause = null;
IASTNode parent = label.getParent();
IASTNode temp = label;
while(!(parent instanceof IASTFunctionDefinition)){
if(parent instanceof IASTDoStatement ||
parent instanceof IASTForStatement ||
parent instanceof IASTWhileStatement ||
parent instanceof IASTSwitchStatement ||
parent instanceof IASTIfStatement){
enclosingStmt = (IASTStatement)parent;
if(parent instanceof IASTIfStatement)
clause = (IASTStatement)temp;
}
if(parent == gotoIfStmt.getParent()) break;
else{
temp = parent;
parent = temp.getParent();
}
}
if(enclosingStmt instanceof IASTDoStatement ||
enclosingStmt instanceof IASTForStatement ||
enclosingStmt instanceof IASTWhileStatement ){
/* parent should be a CompoundStatement */
int gotoindex = -1;
int loopindex = -1;
IASTStatement[] stmts = ((IASTCompoundStatement)parent).getStatements();
for(int i = 0; i<stmts.length; i++){
if(stmts[i] == gotoIfStmt) gotoindex = i;
else if(stmts[i] == enclosingStmt) loopindex = i;
}
IASTCompoundStatement newParentStmt = new CASTCompoundStatement();
for(int i=0; i<gotoindex; i++){
newParentStmt.addStatement(stmts[i]);
stmts[i].setParent(newParentStmt);
}
IASTStatement assignS = makeGotoIfCondStoreStmt(gotoIfStmt.getConditionExpression(), labelname);
newParentStmt.addStatement(assignS);
assignS.setParent(newParentStmt);
if(loopindex - gotoindex > 1){
IASTName condname = new CASTName(labelname.toCharArray());
IASTIdExpression condid = new CASTIdExpression();
condid.setName(condname);
condname.setParent(condid);
IASTUnaryExpression condE = new CASTUnaryExpression();
condE.setOperand(condid);
condE.setOperator(IASTUnaryExpression.op_not);
condid.setParent(condE);
IASTCompoundStatement ifbody = new CASTCompoundStatement();
for(int i=gotoindex+1; i<loopindex; i++){
ifbody.addStatement(stmts[i]);
stmts[i].setParent(ifbody);
}
IASTIfStatement newIfStmt = new CASTIfStatement();
newIfStmt.setConditionExpression(condE);
newIfStmt.setThenClause(ifbody);
newIfStmt.setElseClause(null);
condE.setParent(newIfStmt);
ifbody.setParent(newIfStmt);
newParentStmt.addStatement(newIfStmt);
newIfStmt.setParent(newParentStmt);
}
IASTName loopcondname = new CASTName(labelname.toCharArray());
IASTIdExpression loopcondid = new CASTIdExpression();
loopcondid.setName(loopcondname);
loopcondname.setParent(loopcondid);
IASTStatement loopbody = null;
if(enclosingStmt instanceof IASTDoStatement){
IASTDoStatement doloop = (IASTDoStatement)enclosingStmt;
IASTBinaryExpression newCondE = new CASTBinaryExpression();
IASTExpression oldCondE = doloop.getCondition();
newCondE.setOperand1(oldCondE);
newCondE.setOperand2(loopcondid);
newCondE.setOperator(IASTBinaryExpression.op_logicalOr);
oldCondE.setParent(newCondE);
loopcondid.setParent(newCondE);
((CASTDoStatement)doloop).replace(oldCondE, newCondE);
loopbody = doloop.getBody();
} else if(enclosingStmt instanceof IASTForStatement){
IASTForStatement forloop = (IASTForStatement)enclosingStmt;
IASTBinaryExpression newCondE = new CASTBinaryExpression();
IASTExpression oldCondE = forloop.getConditionExpression();
newCondE.setOperand1(oldCondE);
newCondE.setOperand2(loopcondid);
newCondE.setOperator(IASTBinaryExpression.op_logicalOr);
oldCondE.setParent(newCondE);
loopcondid.setParent(newCondE);
((CASTForStatement)forloop).replace(oldCondE, newCondE);
loopbody = forloop.getBody();
} else if(enclosingStmt instanceof IASTWhileStatement){
IASTWhileStatement whileloop = (IASTWhileStatement)enclosingStmt;
IASTBinaryExpression newCondE = new CASTBinaryExpression();
IASTExpression oldCondE = whileloop.getCondition();
newCondE.setOperand1(oldCondE);
newCondE.setOperand2(loopcondid);
newCondE.setOperator(IASTBinaryExpression.op_logicalOr);
oldCondE.setParent(newCondE);
loopcondid.setParent(newCondE);
((CASTWhileStatement)whileloop).replace(oldCondE, newCondE);
loopbody = whileloop.getBody();
}
IASTCompoundStatement newloopbody = new CASTCompoundStatement();
IASTStatement newGotoS = makeNewGotoIfStmt(labelname, gotoS);
newloopbody.addStatement(newGotoS);
newGotoS.setParent(newloopbody);
if(loopbody instanceof IASTCompoundStatement){
IASTStatement[] bodyStmts = ((IASTCompoundStatement)loopbody).getStatements();
for(int i = 0; i<bodyStmts.length; i++){
newloopbody.addStatement(bodyStmts[i]);
bodyStmts[i].setParent(newloopbody);
}
}
else if(loopbody == label){
newloopbody.addStatement(label);
label.setParent(newloopbody);
}
if(enclosingStmt instanceof IASTDoStatement){
((CASTDoStatement)enclosingStmt).replace(loopbody, newloopbody);
} else if(enclosingStmt instanceof IASTForStatement){
((CASTForStatement)enclosingStmt).replace(loopbody, newloopbody);
} else if(enclosingStmt instanceof IASTWhileStatement){
((CASTWhileStatement)enclosingStmt).replace(loopbody, newloopbody);
}
newParentStmt.addStatement(enclosingStmt);
enclosingStmt.setParent(newParentStmt);
for(int i = loopindex+1; i<stmts.length; i++){
newParentStmt.addStatement(stmts[i]);
stmts[i].setParent(newParentStmt);
}
replaceStatement((IASTStatement)parent, newParentStmt);
}
else if(enclosingStmt instanceof IASTIfStatement){
/* parent must be a compoundStatement */
IASTStatement[] stmts = ((IASTCompoundStatement)parent).getStatements();
int gotoindex = -1;
int ifindex = -1;
for(int i=0; i<stmts.length; i++){
if(stmts[i] == gotoIfStmt) gotoindex = i;
else if(stmts[i] == enclosingStmt) ifindex = i;
}
IASTCompoundStatement newParentStmt = new CASTCompoundStatement();
for(int i=0; i<gotoindex; i++){
newParentStmt.addStatement(stmts[i]);
stmts[i].setParent(newParentStmt);
}
IASTStatement assignS = makeGotoIfCondStoreStmt(gotoIfStmt.getConditionExpression(), labelname);
newParentStmt.addStatement(assignS);
assignS.setParent(newParentStmt);
if(ifindex - gotoindex > 1){
IASTName condname = new CASTName(labelname.toCharArray());
IASTIdExpression condid = new CASTIdExpression();
condid.setName(condname);
condname.setParent(condid);
IASTUnaryExpression condE = new CASTUnaryExpression();
condE.setOperand(condid);
condE.setOperator(IASTUnaryExpression.op_not);
condid.setParent(condE);
IASTCompoundStatement ifbody = new CASTCompoundStatement();
for(int i=gotoindex+1; i<ifindex; i++){
ifbody.addStatement(stmts[i]);
stmts[i].setParent(ifbody);
}
IASTIfStatement newIfStmt = new CASTIfStatement();
newIfStmt.setConditionExpression(condE);
newIfStmt.setThenClause(ifbody);
newIfStmt.setElseClause(null);
condE.setParent(newIfStmt);
ifbody.setParent(newIfStmt);
newParentStmt.addStatement(newIfStmt);
newIfStmt.setParent(newParentStmt);
}
IASTExpression oldIfCond = ((IASTIfStatement)enclosingStmt).getConditionExpression();
IASTName ifcondname = new CASTName(labelname.toCharArray());
IASTIdExpression ifcondid = new CASTIdExpression();
ifcondid.setName(ifcondname);
ifcondname.setParent(ifcondid);
IASTUnaryExpression ifcondPart1 = new CASTUnaryExpression();
ifcondPart1.setOperand(ifcondid);
ifcondPart1.setOperator(IASTUnaryExpression.op_not);
ifcondid.setParent(ifcondPart1);
IASTBinaryExpression newIfCond = new CASTBinaryExpression();
newIfCond.setOperator(IASTBinaryExpression.op_logicalAnd);
newIfCond.setOperand1(ifcondPart1);
newIfCond.setOperand2(oldIfCond);
ifcondPart1.setParent(newIfCond);
oldIfCond.setParent(newIfCond);
((CASTIfStatement)enclosingStmt).replace(oldIfCond, newIfCond);
IASTCompoundStatement newClause = new CASTCompoundStatement();
IASTStatement newGotoS = makeNewGotoIfStmt(labelname, gotoS);
newClause.addStatement(newGotoS);
newGotoS.setParent(newClause);
if(clause instanceof IASTCompoundStatement){
IASTStatement[] clauseStmts = ((IASTCompoundStatement)clause).getStatements();
for(int i = 0; i<clauseStmts.length; i++){
newClause.addStatement(clauseStmts[i]);
clauseStmts[i].setParent(newClause);
}
}
else if(clause == label){
newClause.addStatement(label);
label.setParent(newClause);
}
((CASTIfStatement)enclosingStmt).replace(clause, newClause);
newParentStmt.addStatement(enclosingStmt);
enclosingStmt.setParent(newParentStmt);
for(int i = ifindex+1; i<stmts.length; i++){
newParentStmt.addStatement(stmts[i]);
stmts[i].setParent(newParentStmt);
}
replaceStatement((IASTStatement)parent, newParentStmt);
}
else if(enclosingStmt instanceof IASTSwitchStatement){
/* parent must be a compoundStatement */
IASTStatement[] stmts = ((IASTCompoundStatement)parent).getStatements();
int gotoindex = -1;
int switchindex = -1;
IASTCaseStatement caseStmt = null;
boolean casefound = false;
for(int i=0; i<stmts.length; i++){
if(stmts[i] == gotoIfStmt) gotoindex = i;
else if(stmts[i] == enclosingStmt){
switchindex = i;
casefound = true;
}
else if(stmts[i] instanceof IASTCaseStatement && !casefound){
caseStmt = (IASTCaseStatement)stmts[i];
}
}
IASTCompoundStatement newParentStmt = new CASTCompoundStatement();
for(int i=0; i<gotoindex; i++){
newParentStmt.addStatement(stmts[i]);
stmts[i].setParent(newParentStmt);
}
IASTStatement assignS = makeGotoIfCondStoreStmt(gotoIfStmt.getConditionExpression(), labelname);
newParentStmt.addStatement(assignS);
assignS.setParent(newParentStmt);
/* making new if statement */
IASTName condname = new CASTName(labelname.toCharArray());
IASTIdExpression condid = new CASTIdExpression();
condid.setName(condname);
condname.setParent(condid);
IASTUnaryExpression condE = new CASTUnaryExpression();
condE.setOperand(condid);
condE.setOperator(IASTUnaryExpression.op_not);
condid.setParent(condE);
IASTCompoundStatement ifThenBody = new CASTCompoundStatement();
for(int i=gotoindex+1; i<switchindex; i++){
ifThenBody.addStatement(stmts[i]);
stmts[i].setParent(ifThenBody);
}
String switchvar = "t_switch_" + switch_count; //$NON-NLS-1$
switch_count ++;
createDeclaration(switchvar); /* TODO: fix type information */
IASTName switchCondAssignName = new CASTName(switchvar.toCharArray());
IASTIdExpression switchCondAssignID = new CASTIdExpression();
switchCondAssignID.setName(switchCondAssignName);
switchCondAssignName.setParent(switchCondAssignID);
IASTExpression oldSwitchCondE = ((IASTSwitchStatement)enclosingStmt).getControllerExpression();
IASTBinaryExpression switchCondAssignE = new CASTBinaryExpression();
switchCondAssignE.setOperand1(switchCondAssignID);
switchCondAssignE.setOperand2(oldSwitchCondE);
switchCondAssignE.setOperator(IASTBinaryExpression.op_assign);
switchCondAssignID.setParent(switchCondAssignE);
oldSwitchCondE.setParent(switchCondAssignE);
IASTExpressionStatement switchCondAssignStmt = new CASTExpressionStatement();
switchCondAssignStmt.setExpression(switchCondAssignE);
switchCondAssignE.setParent(switchCondAssignStmt);
ifThenBody.addStatement(switchCondAssignStmt);
switchCondAssignStmt.setParent(ifThenBody);
IASTName elseSwitchCondName = new CASTName(switchvar.toCharArray());
IASTIdExpression elseSwitchCondID = new CASTIdExpression();
elseSwitchCondID.setName(elseSwitchCondName);
elseSwitchCondName.setParent(elseSwitchCondID);
IASTBinaryExpression elseSwitchCondE = new CASTBinaryExpression();
elseSwitchCondE.setOperator(IASTBinaryExpression.op_assign);
elseSwitchCondE.setOperand1(elseSwitchCondID);
elseSwitchCondE.setOperand2(caseStmt.getExpression());
elseSwitchCondID.setParent(elseSwitchCondE);
caseStmt.getExpression().setParent(elseSwitchCondE);
IASTExpressionStatement elseSwitchCondStmt = new CASTExpressionStatement();
elseSwitchCondStmt.setExpression(elseSwitchCondE);
elseSwitchCondE.setParent(elseSwitchCondStmt);
IASTIfStatement newIfStmt = new CASTIfStatement();
newIfStmt.setConditionExpression(condE);
newIfStmt.setThenClause(ifThenBody);
newIfStmt.setElseClause(elseSwitchCondStmt);
condE.setParent(newIfStmt);
ifThenBody.setParent(newIfStmt);
newParentStmt.addStatement(newIfStmt);
newIfStmt.setParent(newParentStmt);
/* end making new if statement */
/* make new switch condition */
IASTName switchCondName = new CASTName(switchvar.toCharArray());
IASTIdExpression switchCondID = new CASTIdExpression();
switchCondID.setName(switchCondName);
switchCondName.setParent(switchCondID);
((CASTSwitchStatement)enclosingStmt).replace(oldSwitchCondE, switchCondID);
/* end make new switch condition */
/* make new switch body */
IASTCompoundStatement newSwitchBody = new CASTCompoundStatement();
IASTStatement oldSwitchBody = ((IASTSwitchStatement)enclosingStmt).getBody();
IASTStatement[] oldSwitchBodyStmts = ((IASTCompoundStatement)oldSwitchBody).getStatements();
for(int i=0; i<oldSwitchBodyStmts.length; i++){
if(oldSwitchBodyStmts[i] != caseStmt){
newSwitchBody.addStatement(oldSwitchBodyStmts[i]);
oldSwitchBodyStmts[i].setParent(newSwitchBody);
} else {
newSwitchBody.addStatement(caseStmt);
caseStmt.setParent(newSwitchBody);
IASTStatement newGotoS = makeNewGotoIfStmt(labelname, gotoS);
newSwitchBody.addStatement(newGotoS);
newGotoS.setParent(newSwitchBody);
}
}
((CASTSwitchStatement)enclosingStmt).replace(oldSwitchBody, newSwitchBody);
newParentStmt.addStatement(enclosingStmt);
enclosingStmt.setParent(newParentStmt);
for(int i = switchindex+1; i<stmts.length; i++){
newParentStmt.addStatement(stmts[i]);
stmts[i].setParent(newParentStmt);
}
replaceStatement((IASTStatement)parent, newParentStmt);
}
}
private void lifting(IASTGotoStatement gotoS){
IASTIfStatement gotoIfStmt = (IASTIfStatement)gotoS.getParent();
String labelname = "goto_" + gotoS.getName().toString(); //$NON-NLS-1$
IASTLabelStatement label = findLabel(gotoS);
IASTStatement enclosingStmt = null;
IASTNode parent = label.getParent();
while(!(parent instanceof IASTFunctionDefinition)){
if(parent instanceof IASTDoStatement ||
parent instanceof IASTForStatement ||
parent instanceof IASTWhileStatement ||
parent instanceof IASTSwitchStatement ||
parent instanceof IASTIfStatement){
enclosingStmt = (IASTStatement)parent;
}
if(parent == gotoIfStmt.getParent()) break;
else{
parent = parent.getParent();
}
}
/* parent should be a CompoundStatement */
IASTStatement[] stmts = ((IASTCompoundStatement)parent).getStatements();
int labelindex = -1;
int gotoindex = -1;
for(int i=0; i<stmts.length; i++){
if(stmts[i] == enclosingStmt) labelindex = i;
else if(stmts[i] == gotoIfStmt) gotoindex = i;
}
IASTCompoundStatement newParentStmt = new CASTCompoundStatement();
for(int i=0; i<labelindex; i++){
newParentStmt.addStatement(stmts[i]);
stmts[i].setParent(newParentStmt);
}
/* make the do loop */
IASTCompoundStatement loopbody = new CASTCompoundStatement();
IASTStatement ifStmt = makeNewGotoIfStmt(labelname, gotoS);
loopbody.addStatement(ifStmt);
ifStmt.setParent(loopbody);
for(int i=labelindex; i<gotoindex; i++){
loopbody.addStatement(stmts[i]);
stmts[i].setParent(loopbody);
}
IASTStatement gotoIfCondStmt = makeGotoIfCondStoreStmt(gotoIfStmt.getConditionExpression(), labelname);
loopbody.addStatement(gotoIfCondStmt);
gotoIfCondStmt.setParent(loopbody);
IASTName condname = new CASTName(labelname.toCharArray());
IASTIdExpression condID = new CASTIdExpression();
condID.setName(condname);
condname.setParent(condID);
IASTDoStatement doStmt = new CASTDoStatement();
doStmt.setBody(loopbody);
doStmt.setCondition(condID);
loopbody.setParent(doStmt);
condID.setParent(doStmt);
/* end make the do loop */
newParentStmt.addStatement(doStmt);
doStmt.setParent(newParentStmt);
for(int i=gotoindex+1; i<stmts.length; i++){
newParentStmt.addStatement(stmts[i]);
stmts[i].setParent(newParentStmt);
}
replaceStatement((IASTStatement)parent, newParentStmt);
}
private void eliminatingGoto(IASTGotoStatement gotoS){
/* gotoS and label should have the same parent, and the parent
* should be a compoundStatement
*/
IASTLabelStatement label = findLabel(gotoS);
IASTIfStatement gotoIfStmt = (IASTIfStatement)gotoS.getParent();
IASTCompoundStatement parent = (IASTCompoundStatement)gotoS.getParent();
IASTStatement[] stmts = parent.getStatements();
int gotoindex = -1;
int labelindex = -1;
for(int i=0; i<stmts.length; i++){
if(stmts[i] == gotoIfStmt) gotoindex = i;
else if(stmts[i] == label) labelindex = i;
}
IASTCompoundStatement newCompS = new CASTCompoundStatement();
if(gotoindex < labelindex){
for(int i=0; i<gotoindex; i++){
newCompS.addStatement(stmts[i]);
stmts[i].setParent(newCompS);
}
if(labelindex - gotoindex > 1){
IASTCompoundStatement newIfBody = new CASTCompoundStatement();
for(int i=gotoindex+1; i<labelindex; i++){
newIfBody.addStatement(stmts[i]);
stmts[i].setParent(newIfBody);
}
IASTUnaryExpression newCondE = new CASTUnaryExpression();
newCondE.setOperator(IASTUnaryExpression.op_not);
newCondE.setOperand(gotoIfStmt.getConditionExpression());
gotoIfStmt.getConditionExpression().setParent(newCondE);
IASTIfStatement newIfS = new CASTIfStatement();
newIfS.setConditionExpression(newCondE);
newIfS.setThenClause(newIfBody);
newIfS.setElseClause(null);
newIfBody.setParent(newIfS);
newCondE.setParent(newIfS);
newCompS.addStatement(newIfS);
newIfS.setParent(newCompS);
}
for(int i=labelindex; i<stmts.length; i++){
newCompS.addStatement(stmts[i]);
stmts[i].setParent(newCompS);
}
}
else { //gotoS occurs later than label
for(int i=0; i<labelindex; i++){
newCompS.addStatement(stmts[i]);
stmts[i].setParent(newCompS);
}
IASTCompoundStatement loopbody = new CASTCompoundStatement();
loopbody.addStatement(label);
label.setParent(loopbody);
for(int i=labelindex+1; i<gotoindex; i++){
loopbody.addStatement(stmts[i]);
stmts[i].setParent(loopbody);
}
IASTDoStatement newLoopS = new CASTDoStatement();
newLoopS.setBody(loopbody);
newLoopS.setCondition(gotoIfStmt.getConditionExpression());
loopbody.setParent(newLoopS);
gotoIfStmt.getConditionExpression().setParent(newLoopS);
newCompS.addStatement(newLoopS);
newLoopS.setParent(newCompS);
for(int i=gotoindex+1; i<stmts.length; i++){
newCompS.addStatement(stmts[i]);
stmts[i].setParent(newCompS);
}
}
replaceStatement(parent, newCompS);
}
private void eliminatingStatement(IASTStatement stmt){
if(stmt instanceof IASTCompoundStatement){
IASTStatement[] stmts = ((IASTCompoundStatement)stmt).getStatements();
int validStmt = 0;
for(int i=0; i<stmts.length; i++){
if(stmts[i] != null) validStmt ++;
}
if(validStmt == 0){ // no valid statement
replaceStatement(stmt, null);
eliminatingStatement((IASTStatement)stmt.getParent());
}
else if(validStmt < stmts.length){ // some statements are not valid
IASTCompoundStatement newCompS = new CASTCompoundStatement();
for(int i=0; i<stmts.length; i++){
if(stmts[i] != null){
newCompS.addStatement(stmts[i]);
stmts[i].setParent(newCompS);
}
}
replaceStatement(stmt, newCompS);
}
} else if(stmt instanceof IASTDoStatement){
IASTDoStatement doS = (IASTDoStatement)stmt;
if(doS.getBody() == null && doS.getCondition() == null){
replaceStatement(stmt, null);
eliminatingStatement((IASTStatement)stmt.getParent());
}
} else if(stmt instanceof IASTForStatement){
} else if(stmt instanceof IASTIfStatement){
IASTIfStatement ifS = (IASTIfStatement)stmt;
if(ifS.getThenClause() == null && ifS.getElseClause() == null){
replaceStatement(stmt, null);
eliminatingStatement((IASTStatement)stmt.getParent());
} else if(ifS.getThenClause() == null && ifS.getElseClause() != null){
IASTIfStatement newIfS = new CASTIfStatement();
IASTUnaryExpression newCondE = new CASTUnaryExpression();
newCondE.setOperator(IASTUnaryExpression.op_not);
newCondE.setOperand(ifS.getConditionExpression());
ifS.getConditionExpression().setParent(newCondE);
newIfS.setConditionExpression(newCondE);
newIfS.setThenClause(ifS.getElseClause());
newIfS.setElseClause(null);
ifS.getElseClause().setParent(newIfS);
newCondE.setParent(newIfS);
replaceStatement(ifS, newIfS);
}
} else if(stmt instanceof IASTLabelStatement){
IASTLabelStatement labelS = (IASTLabelStatement)stmt;
IASTStatement nestedS = labelS.getNestedStatement();
if(nestedS == null){
replaceStatement(stmt, null);
} else {
replaceStatement(stmt, nestedS);
}
eliminatingStatement((IASTStatement)stmt.getParent());
} else if(stmt instanceof IASTSwitchStatement){
} else if(stmt instanceof IASTWhileStatement){
} else {
}
}
/* return statement "labelname = cond;" */
private IASTStatement makeGotoIfCondStoreStmt(IASTExpression cond, String labelname){
IASTName assignName = new CASTName(labelname.toCharArray());
IASTIdExpression assignID = new CASTIdExpression();
assignID.setName(assignName);
assignName.setParent(assignID);
IASTBinaryExpression assignE = new CASTBinaryExpression();
assignE.setOperand1(assignID);
assignE.setOperand2(cond);
assignE.setOperator(IASTBinaryExpression.op_assign);
assignID.setParent(assignE);
cond.setParent(assignE);
IASTExpressionStatement assignS = new CASTExpressionStatement();
assignS.setExpression(assignE);
assignE.setParent(assignS);
return assignS;
}
private IASTStatement makeNewGotoIfStmt(String labelname,
IASTGotoStatement gotoS){
IASTName condname = new CASTName(labelname.toCharArray());
IASTIdExpression condE = new CASTIdExpression();
condE.setName(condname);
condname.setParent(condE);
IASTIfStatement newifStmt = new CASTIfStatement();
newifStmt.setConditionExpression(condE);
newifStmt.setThenClause(gotoS);
newifStmt.setElseClause(null);
condE.setParent(newifStmt);
gotoS.setParent(newifStmt);
return newifStmt;
}
private void replaceStatement(IASTStatement oldS, IASTStatement newS){
IASTNode parent = oldS.getParent();
if(parent instanceof IASTCompoundStatement){
CASTCompoundStatement compS = (CASTCompoundStatement)parent;
compS.replace(oldS, newS);
}
else if(parent instanceof IASTDoStatement){
CASTDoStatement doS = (CASTDoStatement)parent;
doS.replace(oldS, newS);
}
else if(parent instanceof IASTForStatement){
CASTForStatement forS = (CASTForStatement)parent;
forS.replace(oldS, newS);
}
else if(parent instanceof IASTIfStatement){
CASTIfStatement ifS = (CASTIfStatement)parent;
ifS.replace(oldS, newS);
}
else if(parent instanceof IASTSwitchStatement){
CASTSwitchStatement switchS = (CASTSwitchStatement)parent;
switchS.replace(oldS, newS);
}
else if(parent instanceof IASTWhileStatement){
CASTWhileStatement whileS = (CASTWhileStatement)parent;
whileS.replace(oldS, newS);
}
}
/* append "stmt" right after the "prev" */
private void appendStatement(IASTStatement stmt, IASTStatement prev){
IASTCompoundStatement newcompS = new CASTCompoundStatement();
newcompS.addStatement(prev);
newcompS.addStatement(stmt);
prev.setParent(newcompS);
stmt.setParent(newcompS);
replaceStatement(prev, newcompS);
}
private int Level(IASTStatement stmt){
int count = 0;
IASTNode parent = stmt.getParent();
while(! (parent instanceof IASTFunctionDefinition)){
if(parent instanceof IASTIfStatement ||
parent instanceof IASTForStatement ||
parent instanceof IASTDoStatement ||
parent instanceof IASTWhileStatement ||
parent instanceof IASTSwitchStatement)
count ++;
parent = parent.getParent();
}
return count;
}
/* return true if gotoS has lower offset than label, false otherwise */
private boolean Offset(IASTGotoStatement gotoS, IASTLabelStatement label){
OffsetCalculator oc = new OffsetCalculator(currentNode_, gotoS, label);
return oc.gotoBFlabel();
}
class GotoLabelCollector extends ASTVisitor{
private ICallGraphNode node_;
private LinkedList<IASTStatement> gotoList_;
private LinkedList<IASTStatement> labelList_;
public GotoLabelCollector(ICallGraphNode node){
node_ = node;
gotoList_ = new LinkedList<IASTStatement>();
labelList_ = new LinkedList<IASTStatement>();
}
public void run(){
this.shouldVisitDeclarations = true;
this.shouldVisitStatements = true;
IASTStatement body = node_.getFuncDef().getBody();
body.accept(this);
}
public int visit(IASTStatement stmt){
if(stmt instanceof IASTGotoStatement)
gotoList_.add(stmt);
else if(stmt instanceof IASTLabelStatement)
labelList_.add(stmt);
return PROCESS_CONTINUE;
}
public LinkedList getGotoList(){return gotoList_;}
public LinkedList getLabelList() {return labelList_;}
}
class OffsetCalculator extends ASTVisitor{
private ICallGraphNode node_;
private IASTGotoStatement gotoS_;
private IASTLabelStatement labelS_;
private int gotoMet;
private int labelMet;
private int count;
public OffsetCalculator(ICallGraphNode node, IASTGotoStatement gotoS, IASTLabelStatement label){
node_ = node;
gotoS_ = gotoS;
labelS_ = label;
gotoMet = -1;
labelMet = -1;
count = 0;
}
public boolean gotoBFlabel(){
this.shouldVisitStatements = true;
IASTStatement body = node_.getFuncDef().getBody();
body.accept(this);
if(gotoMet == -1 || labelMet == -1){
System.out.println("Goto or label not found!"); //$NON-NLS-1$
} else if(gotoMet > 1 || labelMet > 1){
System.out.println("Multiple gotos and labels are met!"); //$NON-NLS-1$
}
return gotoMet < labelMet;
}
public int visit(IASTStatement stmt){
if(stmt instanceof IASTGotoStatement && stmt == gotoS_){
gotoMet = count;
count ++;
} else if (stmt instanceof IASTLabelStatement && stmt == labelS_){
labelMet = count;
count ++;
}
return PROCESS_CONTINUE;
}
}
}