blob: 0f7b4c41b76b31ec8f37d88848c56b4293fa4f4b [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2013, 2018 CEA LIST and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v20.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<@Nullable CGElement, @NonNull AbstractPlace> element2place = new HashMap<>();
private final @NonNull Set<@NonNull OuterStackPlace> stackPlaces = new HashSet<>();
private final @NonNull Map<@NonNull CGElement, @NonNull SimpleAnalysis> element2simpleAnalysis = new HashMap<>();
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<@NonNull 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<>();
}
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<@NonNull CGValuedElement> getSortedGlobals(@NonNull DependencyVisitor dependencyVisitor) {
if (globalAnalyses.isEmpty()) {
return null;
}
Set<@NonNull CGValuedElement> sortedGlobals = new HashSet<>();
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<@NonNull Integer, @NonNull 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<@NonNull Integer> sortedMaxDepths = new ArrayList<>(depth2commonAnalyses.keySet());
Collections.sort(sortedMaxDepths);
Collections.reverse(sortedMaxDepths);
for (int maxDepth : sortedMaxDepths) {
List<@NonNull CommonAnalysis> commonAnalyses = new ArrayList<>(depth2commonAnalyses.get(maxDepth));
Collections.sort(commonAnalyses);
for (@NonNull 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();
}
}