/*******************************************************************************
* Copyright (c) 2013, 2015 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.List;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.ocl.examples.codegen.analyzer.CodeGenAnalyzer;
import org.eclipse.ocl.examples.codegen.cgmodel.CGConstantExp;
import org.eclipse.ocl.examples.codegen.cgmodel.CGElement;
import org.eclipse.ocl.examples.codegen.cgmodel.CGExecutorType;
import org.eclipse.ocl.examples.codegen.cgmodel.CGLetExp;
import org.eclipse.ocl.examples.codegen.cgmodel.CGModelFactory;
import org.eclipse.ocl.examples.codegen.cgmodel.CGValuedElement;
import org.eclipse.ocl.examples.codegen.cgmodel.CGVariable;
import org.eclipse.ocl.examples.codegen.cgmodel.CGVariableExp;
import org.eclipse.ocl.examples.codegen.utilities.CGUtil;
import org.eclipse.ocl.pivot.internal.utilities.PivotUtilInternal;
public class CommonAnalysis extends AbstractAnalysis
{
private /*@LazyNonNull*/ SimpleAnalysis primaryAnalysis = null;
protected final @NonNull List<SimpleAnalysis> simpleAnalyses = new ArrayList<SimpleAnalysis>();
private int minDepth = Integer.MAX_VALUE;
private int maxDepth = Integer.MIN_VALUE;
public CommonAnalysis(@NonNull SimpleAnalysis firstAnalysis, @NonNull SimpleAnalysis secondAnalysis) {
// this.primaryAnalysis = firstAnalysis;
firstAnalysis.setCommonAnalysis(this);
if (secondAnalysis != firstAnalysis) {
secondAnalysis.setCommonAnalysis(this);
}
}
@Override
public @NonNull CommonAnalysis addAnalysis(@NonNull AbstractAnalysis anAnalysis) {
return anAnalysis.addCommonAnalysis(this);
}
@Override
public @NonNull CommonAnalysis addCommonAnalysis(@NonNull CommonAnalysis commonAnalysis) {
for (@SuppressWarnings("null")@NonNull SimpleAnalysis simpleAnalysis : new ArrayList<SimpleAnalysis>(commonAnalysis.simpleAnalyses)) {
addSimpleAnalysis(simpleAnalysis);
}
return this;
}
@Override
public @NonNull CommonAnalysis addSimpleAnalysis(@NonNull SimpleAnalysis simpleAnalysis) {
simpleAnalysis.setCommonAnalysis(this);
return this;
}
public @NonNull CommonAnalysis addedSimpleAnalysis(@NonNull SimpleAnalysis simpleAnalysis) {
// assert isStructurallyEqualTo(simpleAnalysis);
simpleAnalyses.add(simpleAnalysis);
int depth = simpleAnalysis.getDepth();
if (primaryAnalysis == null) {
primaryAnalysis = simpleAnalysis;
this.minDepth = depth;
this.maxDepth = depth;
}
else if (depth < this.minDepth) {
primaryAnalysis = simpleAnalysis;
this.minDepth = depth;
}
else if (depth > this.maxDepth) {
this.maxDepth = depth;
}
assert primaryAnalysis.isStructurallyEqualTo(simpleAnalysis);
return this;
}
@Override
public int getMaxDepth() {
return maxDepth;
}
@Override
public int getMinDepth() {
return minDepth;
}
@SuppressWarnings("null")
public @NonNull SimpleAnalysis getPrimaryAnalysis() {
return primaryAnalysis;
}
@Override
public @NonNull CGValuedElement getPrimaryElement() {
return primaryAnalysis.getElement();
}
@Override
public int getStructuralHashCode() {
return primaryAnalysis.getStructuralHashCode();
}
@Override
public boolean isStructurallyEqualTo(@NonNull AbstractAnalysis thatAnalysis) {
return primaryAnalysis.isStructurallyEqualTo(thatAnalysis);
}
@Override
public boolean isStructurallyEqualTo(@NonNull SimpleAnalysis thatAnalysis) {
return primaryAnalysis.isStructurallyEqualTo(thatAnalysis);
}
public void removedSimpleAnalysis(SimpleAnalysis simpleAnalysis) {
simpleAnalyses.remove(simpleAnalysis);
}
public void rewrite(@NonNull CodeGenAnalyzer analyzer, @NonNull CGValuedElement controlElement) {
CGValuedElement cgCSE = primaryAnalysis.getElement();
if ((simpleAnalyses.size() > 1) || !cgCSE.isUncommonable()) {
CGVariable cgVariable = CGModelFactory.eINSTANCE.createCGLocalVariable();
cgVariable.setTypeId(cgCSE.getTypeId());
cgVariable.setRequired(cgCSE.isNonNull());
cgVariable.setAst(cgCSE.getAst());
cgVariable.setName(analyzer.getNameManager().getGlobalSymbolName(cgVariable, "_cse"));
for (SimpleAnalysis simpleAnalysis : simpleAnalyses) {
CGValuedElement commonElement = simpleAnalysis.getElement();
CGElement cgParent = commonElement.getParent();
// assert cgParent != null; null if already rewritten by another rewrite
if ((cgParent != null) && !cgParent.rewriteAs(commonElement, cgCSE)) {
rewriteAsVariableExp(commonElement, cgVariable);
}
}
rewriteAsLet(controlElement, cgVariable);
if (cgCSE.eResource() == null) {
PivotUtilInternal.resetContainer(cgCSE);
}
else if (cgCSE instanceof CGExecutorType) {
PivotUtilInternal.resetContainer(cgCSE); // FIXME Bug 439603 is this reparenting valid?
}
else {
PivotUtilInternal.resetContainer(cgCSE); // FIXME Bug 439603 is this reparenting valid?
// CGConstantExp cgConstExp = CGModelFactory.eINSTANCE.createCGConstantExp();
// cgConstExp.setReferredConstant(cgCSE);
// cgCSE = cgConstExp;
}
cgVariable.setInit(cgCSE); // After all rewrites complete
}
}
/**
* Insert a CGLetExp above cgIn for cgCSE.
*/
protected @NonNull CGLetExp rewriteAsLet(@NonNull CGValuedElement cgIn, @NonNull CGVariable cgVariable) {
CGLetExp cgLetExp = CGModelFactory.eINSTANCE.createCGLetExp();
cgLetExp.setTypeId(cgIn.getTypeId());
cgLetExp.setAst(cgIn.getAst());
CGUtil.replace(cgIn, cgLetExp);
cgLetExp.setIn(cgIn);
cgLetExp.setInit(cgVariable);
return cgLetExp;
}
protected void rewriteAsVariableExp(@NonNull CGValuedElement cgElement, @NonNull CGVariable cgVariable) {
CGVariableExp cgVarExp = CGModelFactory.eINSTANCE.createCGVariableExp();
cgVarExp.setTypeId(cgVariable.getTypeId());
cgVarExp.setAst(cgVariable.getAst());
cgVarExp.setReferredVariable(cgVariable);
CGUtil.replace(cgElement, cgVarExp);
}
public void rewriteGlobal(@NonNull CodeGenAnalyzer analyzer) {
if (simpleAnalyses.size() > 1) {
CGConstantExp primaryConstantExp;
CGValuedElement primaryElement = primaryAnalysis.getElement();
if (primaryElement instanceof CGConstantExp) {
primaryConstantExp = (CGConstantExp)primaryElement;
}
else {
CGElement primaryParent = primaryElement.getParent();
if (primaryParent instanceof CGConstantExp) {
primaryConstantExp = (CGConstantExp)primaryParent;
}
else {
primaryConstantExp = CGModelFactory.eINSTANCE.createCGConstantExp();
primaryConstantExp.setReferredConstant(primaryElement);
primaryConstantExp.setAst(primaryElement.getAst());
primaryConstantExp.setTypeId(primaryElement.getTypeId());
primaryConstantExp.setName(primaryElement.getName());
CGUtil.replace(primaryElement, primaryConstantExp);
}
}
for (SimpleAnalysis secondaryAnalysis : simpleAnalyses) {
if (secondaryAnalysis != primaryAnalysis) {
CGConstantExp secondaryConstantExp;
CGValuedElement secondaryElement = secondaryAnalysis.getElement();
if (secondaryElement instanceof CGConstantExp) {
secondaryConstantExp = (CGConstantExp)secondaryElement;
}
else {
CGElement secondaryParent = secondaryElement.getParent();
if (secondaryParent instanceof CGConstantExp) {
secondaryConstantExp = (CGConstantExp)secondaryParent;
}
else {
secondaryConstantExp = CGModelFactory.eINSTANCE.createCGConstantExp();
secondaryConstantExp.setReferredConstant(secondaryElement);
secondaryConstantExp.setAst(secondaryElement.getAst());
secondaryConstantExp.setTypeId(secondaryElement.getTypeId());
secondaryConstantExp.setName(secondaryElement.getName());
CGUtil.replace(secondaryElement, secondaryConstantExp);
}
}
secondaryConstantExp.setReferredConstant(primaryConstantExp.getReferredConstant());
}
}
}
}
@Override
public String toString() {
StringBuilder s = new StringBuilder();
s.append(simpleAnalyses.size() + "," + minDepth + ".." + maxDepth + " ");
s.append(primaryAnalysis);
for (SimpleAnalysis simpleAnalysis : simpleAnalyses) {
if (simpleAnalysis != primaryAnalysis) {
s.append(" ++ " + simpleAnalysis);
}
}
return s.toString();
}
}