/******************************************************************************* * Copyright (c) 2013, 2014 CEA LIST and others. * 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: * E.D.Willink(CEA LIST) - Initial API and implementation *******************************************************************************/ package org.eclipse.ocl.examples.codegen.cse; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.eclipse.jdt.annotation.NonNull; import org.eclipse.jdt.annotation.Nullable; import org.eclipse.ocl.examples.codegen.analyzer.CodeGenAnalyzer; import org.eclipse.ocl.examples.codegen.analyzer.DependencyVisitor; import org.eclipse.ocl.examples.codegen.analyzer.ReferencesVisitor; import org.eclipse.ocl.examples.codegen.cgmodel.CGElement; import org.eclipse.ocl.examples.codegen.cgmodel.CGValuedElement; import org.eclipse.ocl.pivot.utilities.NameUtil; import org.eclipse.ocl.pivot.utilities.StringUtil; import org.eclipse.ocl.pivot.utilities.TracingOption; import com.google.common.collect.HashMultimap; import com.google.common.collect.Multimap; /** * The GlobalPlace describes a forest of CG trees that can be resolved as global constants. */ public class GlobalPlace extends AbstractPlace { public static @NonNull AbstractPlace createGlobalPlace(@NonNull Map<CGElement, AbstractPlace> element2place, @NonNull CGElement cgElement) { AbstractPlace abstractPlace = element2place.get(null); assert abstractPlace != null; return abstractPlace; } protected final @NonNull CodeGenAnalyzer analyzer; protected final @NonNull ReferencesVisitor referencesVisitor; private final @NonNull Map<CGElement, AbstractPlace> element2place = new HashMap<CGElement, AbstractPlace>(); private final @NonNull Set<OuterStackPlace> stackPlaces = new HashSet<OuterStackPlace>(); private final @NonNull Map<CGElement, SimpleAnalysis> element2simpleAnalysis = new HashMap<CGElement, SimpleAnalysis>(); protected final @NonNull HashedAnalyses globalAnalyses = new HashedAnalyses(); public GlobalPlace(@NonNull CodeGenAnalyzer analyzer) { this.analyzer = analyzer; this.referencesVisitor = analyzer.getCodeGenerator().createReferencesVisitor(); } public void addSimpleAnalysis(@NonNull SimpleAnalysis simpleAnalysis) { // System.out.println(ClassUtil.debugSimpleName(simpleAnalysis.getCGElement()) + " => " + ClassUtil.debugSimpleName(simpleAnalysis)); CGValuedElement cgElement = simpleAnalysis.getElement(); element2simpleAnalysis.put(cgElement, simpleAnalysis); if (cgElement.isGlobal() && !cgElement.isInlined()) { assert cgElement.isConstant(); // FIXME debugging globalAnalyses.addSimpleAnalysis(simpleAnalysis); } } void addStackPlace(@NonNull OuterStackPlace stackPlace) { stackPlaces.add(stackPlace); } /** * Populate the map from structural hash code to same-hashed analysis in the analysis tree rooted at thisAnalysis. * <p> * Returns the SimpleAnalysis of cgElement. */ protected @Nullable SimpleAnalysis buildSimpleAnalysisTree(@NonNull CGElement cgElement, int depth) { if (CommonSubexpressionEliminator.CSE_BUILD.isActive()) { CommonSubexpressionEliminator.CSE_BUILD.println(StringUtil.getIndentation(depth, " ") + "Build " + NameUtil.debugSimpleName(cgElement) + " " + StringUtil.convertToOCLString(cgElement.toString())); } // // Create the Place hierarchy in Preorder // AbstractPlace abstractPlace = cgElement.getPlace(element2place); if (abstractPlace == null) { return null; } if (element2place.get(cgElement) == null) { element2place.put(cgElement, abstractPlace); } if (CommonSubexpressionEliminator.CSE_BUILD.isActive()) { CommonSubexpressionEliminator.CSE_BUILD.println(StringUtil.getIndentation(depth, " ") + " ==> " + NameUtil.debugSimpleName(abstractPlace)); } // // Determine the local part of the structural hash code from referenced objects // int structuralHashCode = getStructuralHashCode(cgElement, ""); // // Accumulate the contained part of the structural hash code in a post order traversal // Iterable<? extends CGElement> childElements = cgElement.getChildren(); List<SimpleAnalysis> childAnalyses = null; for (CGElement cgChild : childElements) { if ((cgChild != null) /*&& (cgChild.eContainmentFeature() != CGModelPackage.Literals.CG_VALUED_ELEMENT__OWNS)*/) { SimpleAnalysis childAnalysis = buildSimpleAnalysisTree(cgChild, depth+1); if (childAnalysis != null) { structuralHashCode = 3 * structuralHashCode + childAnalysis.getStructuralHashCode(); if (childAnalyses == null) { childAnalyses = new ArrayList<SimpleAnalysis>(); } childAnalyses.add(childAnalysis); } } } if (!(cgElement instanceof CGValuedElement)) { return null; } CGValuedElement cgValuedElement = (CGValuedElement)cgElement; // System.out.println("Build2 " + ClassUtil.debugSimpleName(cgElement)); if (CommonSubexpressionEliminator.CSE_BUILD.isActive()) { CommonSubexpressionEliminator.CSE_BUILD.println(StringUtil.getIndentation(depth, " ") + "=> " + NameUtil.debugSimpleName(abstractPlace) + " " + structuralHashCode); } if (abstractPlace != this) { // FIXME Ugh! StackPlace stackPlace = abstractPlace.getStackPlace(); if (stackPlace == null) { return null; } if ((cgValuedElement == stackPlace.getStackElement()) && (stackPlace instanceof OuterStackPlace)) { return null; } } // System.out.println("Build3 " + ClassUtil.debugSimpleName(cgElement)); // System.out.println("new " + structuralHashCode + " " + ClassUtil.debugSimpleName(cgValuedElement) + " " + cgValuedElement.toString()); SimpleAnalysis structuralAnalysis; if (childAnalyses != null) { @SuppressWarnings("null")@NonNull SimpleAnalysis @NonNull [] childArray = childAnalyses.toArray(new SimpleAnalysis[childAnalyses.size()]); structuralAnalysis = new SimpleAnalysis(this, cgValuedElement, depth, structuralHashCode, childArray); } else { structuralAnalysis = new SimpleAnalysis(this, cgValuedElement, depth, structuralHashCode, SimpleAnalysis.EMPTY_LIST); } if (CommonSubexpressionEliminator.CSE_BUILD.isActive()) { CommonSubexpressionEliminator.CSE_BUILD.println(StringUtil.getIndentation(depth, " ") + "=> " + NameUtil.debugSimpleName(structuralAnalysis) + " " + structuralAnalysis.toString()); } return structuralAnalysis; } public @NonNull CodeGenAnalyzer getAnalyzer() { return analyzer; } public @NonNull ControlPlace getControlPlace(@NonNull CGValuedElement cgElement) { AbstractPlace abstractPlace = element2place.get(cgElement); if (abstractPlace instanceof ControlPlace) { return (ControlPlace) abstractPlace; } else { throw new IllegalStateException("Not ControlPlace " + abstractPlace); } } @Override public @NonNull GlobalPlace getGlobalPlace() { return this; } @Override public @NonNull GlobalPlace getParentPlace() { return this; } public @Nullable AbstractPlace getPlace(@NonNull CGElement cgElement) { return element2place.get(cgElement); } public @NonNull ReferencesVisitor getReferencesVisitor() { return referencesVisitor; } public @Nullable SimpleAnalysis getSimpleAnalysis(@NonNull Object anObject) { return element2simpleAnalysis.get(anObject); } public @Nullable List<CGValuedElement> getSortedGlobals(@NonNull DependencyVisitor dependencyVisitor) { if (globalAnalyses.isEmpty()) { return null; } Set<CGValuedElement> sortedGlobals = new HashSet<CGValuedElement>(); for (AbstractAnalysis analysis : globalAnalyses) { CGValuedElement value = analysis.getPrimaryElement().getNamedValue(); assert value.isGlobal(); sortedGlobals.add(value); } dependencyVisitor.visitAll(sortedGlobals); return dependencyVisitor.getSortedDependencies(true); } @Override public @Nullable StackPlace getStackPlace() { return null; } protected int getStructuralHashCode(@NonNull CGElement cgElement, @NonNull String prefix) { // System.out.println(prefix + "getStructuralHashCode " + ClassUtil.debugSimpleName(cgElement) + " " + cgElement.toString()); int structuralHashCode = cgElement.getClass().getName().hashCode(); // System.out.println(prefix + " class " + structuralHashCode); List<@Nullable Object> referencedObjects = cgElement.accept(referencesVisitor); for (@Nullable Object referencedObject : referencedObjects) { int referenceHashCode = 1; if (referencedObject != null) { if (referencedObject instanceof CGElement) { referenceHashCode = getStructuralHashCode((CGElement) referencedObject, prefix + " "); } else { referenceHashCode = referencedObject.hashCode(); } // System.out.println(prefix + " ref " + referenceHashCode + " " + ClassUtil.debugSimpleName(referencedObject) + " " + referencedObject.toString()); } structuralHashCode = 3 * structuralHashCode + referenceHashCode; } // System.out.println(prefix + " = " + structuralHashCode + " " + ClassUtil.debugSimpleName(cgElement) + " " + cgElement.toString()); return structuralHashCode; } /** * Optimize the cgRoot tree by eliminating common subexpressions. */ public void optimize(@NonNull CGElement cgRoot) { element2place.put(null, this); element2place.put(cgRoot, this); // // Analyze the tree to create an analysis per node and a partitioning into Places // with a Map from structural hash code to analysis in each Place. // buildSimpleAnalysisTree(cgRoot, 0); // if (CommonSubexpressionEliminator.CSE_PLACES.isActive()) { CommonSubexpressionEliminator.CSE_PLACES.println("Places"); printHierarchy(CommonSubexpressionEliminator.CSE_PLACES, ""); } // // Optimize each outer stack place. // for (OuterStackPlace stackPlace : stackPlaces) { stackPlace.optimize(); } optimizeGlobals(cgRoot); } public void optimizeGlobals(@NonNull CGElement cgRoot) { // // Rewrite shared analyses as LetExps, VarExps. // if (!globalAnalyses.isEmpty()) { Multimap<Integer, CommonAnalysis> depth2commonAnalyses = HashMultimap.create(); for (AbstractAnalysis analysis : globalAnalyses) { if (analysis instanceof CommonAnalysis) { CommonAnalysis commonAnalysis = (CommonAnalysis)analysis; int maxDepth = commonAnalysis.getMaxDepth(); depth2commonAnalyses.put(maxDepth, commonAnalysis); } } List<Integer> sortedMaxDepths = new ArrayList<Integer>(depth2commonAnalyses.keySet()); Collections.sort(sortedMaxDepths); Collections.reverse(sortedMaxDepths); for (int maxDepth : sortedMaxDepths) { List<CommonAnalysis> commonAnalyses = new ArrayList<CommonAnalysis>(depth2commonAnalyses.get(maxDepth)); Collections.sort(commonAnalyses); for (CommonAnalysis commonAnalysis : commonAnalyses) { commonAnalysis.rewriteGlobal(analyzer); } } } if (CommonSubexpressionEliminator.CSE_REWRITE.isActive()) { CommonSubexpressionEliminator.CSE_REWRITE.println("Places after rewrite"); printHierarchy(CommonSubexpressionEliminator.CSE_REWRITE, ""); @NonNull String string = String.valueOf(cgRoot); TracingOption.println(CommonSubexpressionEliminator.CSE_REWRITE, string); } } @Override public void printHierarchy(@NonNull Appendable appendable, @NonNull String indentation) { TracingOption.println(appendable, indentation + "GlobalPlace"); if (!globalAnalyses.isEmpty()) { for (AbstractAnalysis analysis : globalAnalyses) { TracingOption.println(appendable, indentation + " " + analysis.getStructuralHashCode() + "," + analysis); } } else { TracingOption.println(appendable, indentation + " <empty>"); } for (OuterStackPlace stackPlace : stackPlaces) { stackPlace.printHierarchy(appendable, indentation + " "); } } @Override public String toString() { return getClass().getSimpleName(); } }