blob: ff3b71bebeda4dbad006d4385fc3c06e60385116 [file] [log] [blame]
/**********************************************************************
* Copyright (c) 2006,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.openmp.analysis;
import java.util.Set;
import java.util.Stack;
import org.eclipse.cdt.core.dom.CDOM;
import org.eclipse.cdt.core.dom.IASTServiceProvider;
import org.eclipse.cdt.core.dom.ast.IASTNode;
import org.eclipse.cdt.core.dom.ast.IASTPreprocessorStatement;
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
import org.eclipse.core.resources.IFile;
import org.eclipse.jface.text.IDocument;
import org.eclipse.ptp.pldt.common.util.Utility;
import org.eclipse.ptp.pldt.openmp.analysis.PAST.PASTElif;
import org.eclipse.ptp.pldt.openmp.analysis.PAST.PASTElse;
import org.eclipse.ptp.pldt.openmp.analysis.PAST.PASTEndif;
import org.eclipse.ptp.pldt.openmp.analysis.PAST.PASTFactory;
import org.eclipse.ptp.pldt.openmp.analysis.PAST.PASTIf;
import org.eclipse.ptp.pldt.openmp.analysis.PAST.PASTIfdef;
import org.eclipse.ptp.pldt.openmp.analysis.PAST.PASTIfndef;
import org.eclipse.ptp.pldt.openmp.analysis.PAST.PASTNode;
import org.eclipse.ptp.pldt.openmp.analysis.PAST.PASTOMPFactory;
import org.eclipse.ptp.pldt.openmp.analysis.PAST.PASTOMPPragma;
import org.eclipse.ptp.pldt.openmp.analysis.PAST.PASTPragma;
import org.eclipse.ptp.pldt.openmp.analysis.dictionary.Dictionary;
import org.eclipse.ptp.pldt.openmp.analysis.dictionary.DictionaryFactory;
import org.eclipse.ptp.pldt.openmp.analysis.ompcfg.factory.FileConcurrencyAnalysis;
import org.eclipse.ptp.pldt.openmp.analysis.ompcfg.factory.FileStatementMap;
import org.eclipse.ptp.pldt.openmp.analysis.ompcfg.factory.FunctionConcurrencyAnalysis;
/**
* @author pazel
*/
public class OpenMPAnalysisManager
{
protected IASTTranslationUnit astTransUnit_ = null;
protected IFile iFile_ = null;
protected PASTNode [] past_ = null;
protected PASTOMPPragma [] ompPragmas_ = null;
protected FileConcurrencyAnalysis fileAnalysis_ = null;
protected FunctionConcurrencyAnalysis [] analyses_ = null;
protected FileStatementMap fileMap_ = null;
private static final boolean traceOn = false;
protected Dictionary dictionary_ = null;
protected OpenMPErrorManager errorManager_ = new OpenMPErrorManager();
protected static OpenMPAnalysisManager currentManager_ = null;
/**
* Constructor called by eclipse
* @param file
* @throws OpenMPAnalysisException
*/
public OpenMPAnalysisManager(final IFile iFile) throws OpenMPAnalysisException
{
try {
astTransUnit_ = CDOM.getInstance().getASTService().getTranslationUnit(iFile,
CDOM.getInstance().getCodeReaderFactory(CDOM.PARSE_SAVED_RESOURCES));
}
catch(IASTServiceProvider.UnsupportedDialectException e) {
throw new OpenMPAnalysisException(e.toString());
}
iFile_ = iFile;
init();
currentManager_ = this;
}
/**
* Constructor used by testing mechanism
* @param astTransUnit
*/
public OpenMPAnalysisManager(IASTTranslationUnit astTransUnit, IFile iFile)
{
astTransUnit_ = astTransUnit;
iFile_ = iFile;
init();
currentManager_ = this;
}
/**
* Get the last analysis manager built
* @return OpenMPAnalysisManager
*/
public static OpenMPAnalysisManager getCurrentManager()
{
return currentManager_;
}
/**
* main logic invoked by both constructors
*
*/
private void init()
{
// Note: throughout all this, it is best to use the same AST instance, i.e.
// don't re-gen it, as references to nodes may be made by various components
// that should hold up under equality.
buildPreprocessorAST();
buildDictionary();
buildOMPPragmas();
buildOMPConcurrencyAnalysis();
buildFileMap();
//buildDomoCDT();
}
/**
* Build all the nodes, compute which compiled
*
*/
private void buildPreprocessorAST()
{
IASTPreprocessorStatement[] plist = astTransUnit_.getAllPreprocessorStatements();
past_ = new PASTNode[plist.length];
for(int i=0; i<plist.length; i++)
past_[i] = PASTFactory.PASTFactoryMake(plist[i]);
// Set the compiled flags to show live and dead preprocessor statements
computeCompiled();
}
/**
* Build the "variable" dictionary
*
*/
private void buildDictionary()
{
dictionary_ = DictionaryFactory.buildDictionary(astTransUnit_);
}
// private void buildDomoCDT()
// {
// CDTTranslateToCAst ctrans = new CDTAST2CAstTranslator(new IASTNodeFactory_c());
// CAstEntity entity = ctrans.translate(astTransUnit_);
//
// PrintWriter printWriter= new PrintWriter(System.out);
//
// CAstPrinter.printTo(entity, printWriter);
// printWriter.flush();
//
// }
/**
* Build the OMP style pragmas
*
*/
private void buildOMPPragmas()
{
int pCount = 0;
IDocument pragmaDoc = null;
String filename = "";
for(int i=0; i<past_.length; i++) {
if (past_[i] instanceof PASTPragma) {
PASTPragma pragma = (PASTPragma)past_[i];
//
// For each of these, get the content
//
String newFileName = ((PASTPragma)past_[i]).getContainingFilename();
if (!filename.equals(newFileName)) {
filename = newFileName;
pragmaDoc = Utility.getDocument(filename);
}
if (pragmaDoc!=null) {
try {
String content = pragmaDoc.get(pragma.getLocalOffset(), pragma.getLength());
pragma.setContent(content);
}
catch(Exception e) {}
}
past_[i] = PASTOMPFactory.makePASTOMP((PASTPragma)past_[i], astTransUnit_, dictionary_);
// if successful, would be an omp
if (past_[i] instanceof PASTOMPPragma)
pCount++;
}
}
// build the pragma list
int index = 0;
ompPragmas_ = new PASTOMPPragma[pCount];
for(int i=0; i<past_.length; i++) {
if (past_[i] instanceof PASTOMPPragma)
ompPragmas_[index++] = (PASTOMPPragma)past_[i];
}
if(traceOn)printPASTResults();
}
/**
* Build concurrency analysis
*
*/
private void buildOMPConcurrencyAnalysis()
{
fileAnalysis_ = new FileConcurrencyAnalysis(astTransUnit_,
iFile_,
getOMPPragmas());
/*DefVisitor dv = new DefVisitor(astTransUnit_, iFile_, getOMPPragmas());
analyses_ = dv.buildAnalyses();
// build the phase analysis
for(int i=0; i<analyses_.length; i++) {
FunctionConcurrencyAnalysis oca = analyses_[i];
oca.doPhaseAnalysis();
if (traceOn) oca.printAnalysis(System.out);
}*/
}
/**
* Build the location-->stmt/expr map
*
*/
protected void buildFileMap()
{
// Note - important that we use SAME AST for all analysis and lookup
fileMap_ = new FileStatementMap(astTransUnit_);
fileMap_.buildMap();
}
/**
* Get the pragma AST tree
* @return PASTNode []
*/
public PASTNode [] getPAST()
{
return past_;
}
/**
* Return a list of PASTOMPPragmas
* @return
*/
public PASTOMPPragma [] getOMPPragmas()
{
return ompPragmas_;
}
/**
* Return IASTTranslationUnit
* @return IASTTranslationUnit
*/
public IASTTranslationUnit getTU()
{
return astTransUnit_;
}
/**
* Accessor to the file map for analyzed file
* @return FileStatementMap
*/
public FileStatementMap getFileMap()
{
return fileMap_;
}
/**
* Get the analysis for each function
* @return FunctionConcurrencyAnalysis []
*/
public FunctionConcurrencyAnalysis [] getAnalyses()
{ return analyses_; }
/**
* Get all nodes concurrent to given node
* @param node - IASTNode
* @return Set
*/
public Set getNodesConcurrentTo(IASTNode node)
{
return fileAnalysis_.getNodesConcurrentTo(node);
}
/**
* Prints out results for debugging
*
*/
protected void printPASTResults()
{
// output the results
for(int i=0; i<past_.length; i++) {
System.out.print(past_[i].getType()+" "+(past_[i].isCompiled() ? "compiled": "not compiled"));
System.out.print(" at ("+ past_[i].getFilename()+","+past_[i].getStartingLine()+","+
past_[i].getStartLocation()+","+past_[i].getEndLocation()+") ");
if (past_[i] instanceof PASTOMPPragma) {
int t = ((PASTOMPPragma)past_[i]).getOMPType();
System.out.println(" OMPPragma type="+t);
}
else System.out.println("");
}
}
/**
* Compute which statements compiled
*
*/
private void computeCompiled()
{
Stack context = new Stack();
boolean currentEvaluation = true;
int currentLevel = 0;
int lastNonIgnoredIf = currentLevel;
context.push(new CompiledContext(currentLevel, currentEvaluation));
int ifcount=0;
int endifcount=0;
int i=0;
for(i=0; i<past_.length; i++) {
PASTNode node = past_[i];
if(node==null){
int stopHere=0;
}
if (currentEvaluation) {
if (isIf(node)) {
currentEvaluation = ifDecision(node);
currentLevel++; lastNonIgnoredIf++;
context.push(new CompiledContext(currentLevel, currentEvaluation));
ifcount++;
}
else if (isElse(node)) {
currentEvaluation = false;
if (context.empty()) break;
((CompiledContext)(context.peek())).setEvaluation(currentEvaluation);
}
else if (isElseif(node)) {
CompiledContext cc = ((CompiledContext)(context.peek()));
cc.setWasTrue(true);
currentEvaluation = false;
// Don't bump the level
cc.setEvaluation(false);
}
else if (isEnd(node)) {
if (context.empty()) break;
context.pop();
currentLevel--; lastNonIgnoredIf--;
if (context.empty()) break;
currentEvaluation = ((CompiledContext)(context.peek())).getEvaluation();
endifcount++;
}
node.setCompiled(true);
}
else { // current evaluation == false
if (currentLevel==lastNonIgnoredIf) {
if (isIf(node)) {
currentLevel++;
node.setCompiled(false);
ifcount++;
}
else if (isElse(node)) {
CompiledContext cc = ((CompiledContext)(context.peek()));
if (cc.wasTrue())
currentEvaluation = false;
else
currentEvaluation = true;
if (context.empty()) break;
((CompiledContext)(context.peek())).setEvaluation(currentEvaluation);
node.setCompiled(true); // means was not ignored - had effect
}
else if (isElseif(node)) {
CompiledContext cc = ((CompiledContext)(context.peek()));
if (cc.wasTrue())
currentEvaluation = false;
else {
currentEvaluation = ifDecision(node);
if (currentEvaluation) cc.setWasTrue(true);
}
// Don't bump the level
cc.setEvaluation(currentEvaluation);
}
else if (isEnd(node)) {
context.pop();
currentLevel--; lastNonIgnoredIf--;
if (context.empty()) break;
currentEvaluation = ((CompiledContext)(context.peek())).getEvaluation();
node.setCompiled(currentEvaluation);
endifcount++;
}
else
node.setCompiled(false);
}
else {
if (isIf(node)) {
currentLevel++;
ifcount++;
}
else if (isEnd(node)) {
currentLevel--;
endifcount++;
}
node.setCompiled(false);
}
}
}
}
/**
* Determine if node is a branch
* @param node
* @return
*/
private boolean isIf(PASTNode node)
{
return (node instanceof PASTIf) || (node instanceof PASTIfdef) || (node instanceof PASTIfndef);
}
/**
* Retrieve the compile decision of the 'if' condition
* @param node
* @return
*/
private boolean ifDecision(PASTNode node)
{
if (node instanceof PASTIf) return ((PASTIf)node).taken();
else if (node instanceof PASTIfdef) return ((PASTIfdef)node).taken();
else if (node instanceof PASTIfndef) return ((PASTIfndef)node).taken();
else
return false;
}
/**
* Determine if the node is of 'else' kind
* @param node
* @return
*/
private boolean isElse(PASTNode node)
{
return (node instanceof PASTElse);
}
/**
* Determine if the node is of 'elseif' kind
* @param node
* @return
*/
private boolean isElseif(PASTNode node)
{
return (node instanceof PASTElif);
}
/**
* Determine if node is of 'end' kind
* @param node
* @return
*/
private boolean isEnd(PASTNode node)
{
return (node instanceof PASTEndif);
}
/**
* Stack object used for evaluating "compiled" state of PP's
*/
private static class CompiledContext
{
private boolean evaluation_ = false;
private int nestedLevel_ = 0;
private boolean wasTrue_ = false; // used for elif situations
public CompiledContext(int nestedLevel, boolean evaluation)
{
evaluation_ = evaluation;
nestedLevel_ = nestedLevel;
}
public boolean getEvaluation()
{
return evaluation_;
}
public void setEvaluation(boolean evaluation)
{
evaluation_ = evaluation;
}
public int getNestedLevel()
{
return nestedLevel_;
}
public boolean wasTrue() { return wasTrue_; }
public void setWasTrue(boolean tf) { wasTrue_=tf; }
}
}