blob: b2d14aaedb75fd6a53488c8e431e61045b536a75 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2016, 2019 Willink Transformations 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 - Initial API and implementation
*******************************************************************************/
package org.eclipse.qvtd.compiler.internal.qvts2qvts.partitioner;
import java.util.HashSet;
import java.util.Set;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.ocl.pivot.internal.utilities.PivotUtilInternal;
import org.eclipse.qvtd.compiler.internal.qvtb2qvts.ScheduleManager;
import org.eclipse.qvtd.compiler.internal.qvtm2qvts.QVTm2QVTs;
import org.eclipse.qvtd.compiler.internal.qvts2qvts.utilities.ReachabilityForest;
import org.eclipse.qvtd.pivot.qvtschedule.BasicPartition;
import org.eclipse.qvtd.pivot.qvtschedule.Edge;
import org.eclipse.qvtd.pivot.qvtschedule.MergedPartition;
import org.eclipse.qvtd.pivot.qvtschedule.NavigableEdge;
import org.eclipse.qvtd.pivot.qvtschedule.Node;
import org.eclipse.qvtd.pivot.qvtschedule.Region;
import org.eclipse.qvtd.pivot.qvtschedule.Role;
import org.eclipse.qvtd.pivot.qvtschedule.utilities.QVTscheduleUtil;
import com.google.common.collect.Iterables;
/**
* The Merged Partition aggregates the nodes and edges of multipl,e partitions as a single merged partition.
*/
public class MergedPartitionFactory extends AbstractPartitionFactory<@NonNull Region>
{
protected final @NonNull Iterable<@NonNull BasicPartitionAnalysis> subPartitionAnalyses;
public MergedPartitionFactory(@NonNull ScheduleManager scheduleManager, @NonNull Region region, @NonNull Iterable<@NonNull BasicPartitionAnalysis> subPartitionAnalyses) {
super(scheduleManager, region);
this.subPartitionAnalyses = subPartitionAnalyses;
}
protected void addNode(@NonNull BasicPartition partition, @NonNull Node node, @NonNull Role newNodeRole) {
assert node.getOwningRegion() == region;
Role displacedNodeRole = partition.putNodeRole(node, newNodeRole);
assert displacedNodeRole == null;
}
protected @NonNull String computeName() {
StringBuilder s = new StringBuilder();
s.append(region.getName() + "«");
boolean isFirst = true;
for (@NonNull BasicPartitionAnalysis subPartitionAnalysis : subPartitionAnalyses) {
if (!isFirst) {
s.append(",");
}
String name = subPartitionAnalysis.getName();
int iStart = name.indexOf('«');
int iFinish = name.indexOf('»');
if ((0 <= iStart) && (iStart < iFinish)) {
s.append(name.subSequence(iStart+1, iFinish));
}
else {
s.append(name);
}
isFirst = false;
}
s.append("»");
return s.toString();
}
@Override
public @NonNull BasicPartitionAnalysis createPartitionAnalysis(@NonNull PartitionedTransformationAnalysis partitionedTransformationAnalysis) {
BasicPartition partition = subPartitionAnalyses.iterator().next().getPartition();
Iterable<@NonNull Node> headNodes = QVTscheduleUtil.getHeadNodes(partition);
MergedPartition mergedPartition = createMergedPartition(computeName(), headNodes);
for (@NonNull BasicPartitionAnalysis subPartitionAnalysis : subPartitionAnalyses) {
BasicPartition subPartition = subPartitionAnalysis.getPartition();
PivotUtilInternal.resetContainer(subPartition);
mergedPartition.getOwnedMergedPartitions().add(subPartition);
mergedPartition.getExplicitPredecessors().addAll(subPartition.getExplicitPredecessors());
mergedPartition.getExplicitSuccessors().addAll(subPartition.getExplicitSuccessors());
}
return createPartitionAnalysis(partitionedTransformationAnalysis, mergedPartition);
}
protected @NonNull BasicPartitionAnalysis createPartitionAnalysis(@NonNull PartitionedTransformationAnalysis partitionedTransformationAnalysis, @NonNull MergedPartition mergedPartition) {
ReachabilityForest reachabilityForest = createReachabilityForest();
int partitionNumber = region.getNextPartitionNumber();
String namePrefix = "«merge" + partitionNumber + "»";
String symbolSuffix = "_p" + partitionNumber;
BasicPartitionAnalysis basicPartitionAnalysis = new BasicPartitionAnalysis(partitionedTransformationAnalysis, mergedPartition, reachabilityForest, namePrefix, symbolSuffix);
initializePartition(basicPartitionAnalysis);
basicPartitionAnalysis.analyzePartition();
basicPartitionAnalysis.analyzePartition2();
if (QVTm2QVTs.DEBUG_GRAPHS.isActive()) {
scheduleManager.writeDebugGraphs(basicPartitionAnalysis.getPartition(), null);
}
return basicPartitionAnalysis;
}
@Override
protected @NonNull Iterable<@NonNull NavigableEdge> getAvailableNavigableEdges() {
Set<@NonNull NavigableEdge> oldEdges = new HashSet<>(); //
Set<@NonNull NavigableEdge> realizedEdges = new HashSet<>(); //
for (@NonNull BasicPartitionAnalysis subPartitionAnalysis : subPartitionAnalyses) {
BasicPartition partition = subPartitionAnalysis.getPartition();
for (@NonNull Edge edge : partition.getPartialEdges()) {
if (edge.isNavigation()) {
if (subPartitionAnalysis.isRealized(edge)) {
realizedEdges.add((NavigableEdge) edge);
}
else if (subPartitionAnalysis.isOld(edge)) {
oldEdges.add((NavigableEdge) edge);
}
}
}
}
oldEdges.removeAll(realizedEdges); // FIXME ?? conditional / computation
return oldEdges;
}
@Override
protected @NonNull Iterable<@NonNull Node> getReachabilityRootNodes() {
Set<@NonNull Node> rootNodes = new HashSet<>();
for (@NonNull BasicPartitionAnalysis subPartitionAnalysis : subPartitionAnalyses) {
ReachabilityForest reachabilityForest = subPartitionAnalysis.getReachabilityForest();
for (@NonNull Node node : reachabilityForest.getNodes()) {
if (reachabilityForest.getCost(node) == 0) {
rootNodes.add(node);
}
}
}
return rootNodes;
}
protected void initializePartition(@NonNull BasicPartitionAnalysis partitionAnalysis) {
BasicPartition partition = partitionAnalysis.getPartition();
// this.traceNode = mappingPartitioner.getTraceNode();
//
// Add all the nodes merging the roles.
//
Set<@NonNull Node> mergedNodes = new HashSet<>();
Set<@NonNull Edge> mergedEdges = new HashSet<>();
for (@NonNull BasicPartitionAnalysis subPartitionAnalysis : subPartitionAnalyses) {
BasicPartition subPartition = subPartitionAnalysis.getPartition();
Iterables.addAll(mergedNodes, subPartition.getPartialNodes());
Iterables.addAll(mergedEdges, subPartition.getPartialEdges());
}
//
// Add all the nodes merging the roles.
//
for (@NonNull Node mergedNode : mergedNodes) {
mergeNode(partition, mergedNode);
}
//
// Add all the edges merging the roles.
//
for (@NonNull Edge edge : mergedEdges) {
mergeEdge(partition, edge);
}
}
/**
* Merge the edge merging the roles.
*/
protected void mergeEdge(@NonNull BasicPartition partition, @NonNull Edge edge) {
boolean isConstant = false;
boolean isLoaded = false;
boolean isPredicated = false;
boolean isRealized = false;
boolean isSpeculated = false;
for (@NonNull BasicPartitionAnalysis subPartitionAnalysis : subPartitionAnalyses) {
Role role = subPartitionAnalysis.getPartition().getRole(edge);
if (role != null) {
switch (role) {
case CONSTANT: isConstant = true; break;
case LOADED: isLoaded = true; break;
case PREDICATED: isPredicated = true; break;
case REALIZED: isRealized = true; break;
case SPECULATED: isSpeculated = true; break;
default: throw new UnsupportedOperationException();
}
}
}
if (isConstant) {
addEdge(partition, edge, Role.CONSTANT);
}
else if (isLoaded) {
addEdge(partition, edge, Role.LOADED);
}
else if (isRealized) {
addEdge(partition, edge, Role.REALIZED);
}
else if (isSpeculated) {
addEdge(partition, edge, Role.SPECULATED);
}
else if (isPredicated) {
addEdge(partition, edge, Role.PREDICATED);
}
else {
throw new UnsupportedOperationException();
}
}
/**
* Merge the node merging the roles.
*/
protected void mergeNode(@NonNull BasicPartition partition, @NonNull Node node) {
boolean isConstant = false;
boolean isConstantSuccessFalse = false;
boolean isConstantSuccessTrue = false;
boolean isLoaded = false;
boolean isPredicated = false;
boolean isRealized = false;
boolean isSpeculated = false;
boolean isSpeculation = false;
for (@NonNull BasicPartitionAnalysis subPartitionAnalysis : subPartitionAnalyses) {
Role role = subPartitionAnalysis.getPartition().getRole(node);
if (role != null) {
switch (role) {
case CONSTANT: isConstant = true; break;
case CONSTANT_SUCCESS_FALSE: isConstantSuccessFalse = true; break;
case CONSTANT_SUCCESS_TRUE: isConstantSuccessTrue = true; break;
case LOADED: isLoaded = true; break;
case PREDICATED: isPredicated = true; break;
case REALIZED: isRealized = true; break;
case SPECULATED: isSpeculated = true; break;
case SPECULATION: isSpeculation = true; break;
default: throw new UnsupportedOperationException();
}
}
}
if (isConstant) {
addNode(partition, node, Role.CONSTANT);
}
else if (isConstantSuccessFalse) {
addNode(partition, node, Role.CONSTANT_SUCCESS_FALSE);
}
else if (isConstantSuccessTrue) {
addNode(partition, node, Role.CONSTANT_SUCCESS_TRUE);
}
else if (isLoaded) {
addNode(partition, node, Role.LOADED);
}
else if (isRealized) {
addNode(partition, node, Role.REALIZED);
}
else if (isSpeculation) {
addNode(partition, node, isSpeculated ? Role.REALIZED : Role.SPECULATION);
}
else if (isSpeculated) {
addNode(partition, node, Role.SPECULATED);
}
else if (isPredicated) {
addNode(partition, node, Role.PREDICATED);
}
else {
throw new UnsupportedOperationException();
}
}
@Override
protected @Nullable Role resolveEdgeRole(@NonNull Role sourceNodeRole, @NonNull Edge edge, @NonNull Role targetNodeRole) {
throw new UnsupportedOperationException(); // Never called since resolveEdges() not called.
}
@Override
public @NonNull String toString() {
return super.toString() + " " + subPartitionAnalyses;
}
}