| /********************************************************************** |
| * 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; } |
| } |
| } |