package de.gaalop.gapp.importing.optimization;
import de.gaalop.gapp.visitor.EmptyCFGGAPPVisitor;
import de.gaalop.cfg.AssignmentNode;
import de.gaalop.cfg.EndNode;
import de.gaalop.gapp.instructionSet.GAPPSetMv;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
/**
* Optimizes the GAPP Code by
* merging setMv instructions with equal multivector name, if possible.
*
* @author Christian Steinmetz
*/
public class GAPPSetMvMerger extends EmptyCFGGAPPVisitor {
private HashSet<GAPPSetMv> toRemove = new HashSet<GAPPSetMv>();
public HashSet<GAPPSetMv> getToRemove() {
return toRemove;
}
private String curDestination;
private HashMap<String, LinkedList<GAPPSetMv>> mapSetMv = new HashMap<String, LinkedList<GAPPSetMv>>();
@Override
public void visit(AssignmentNode node) {
String varName = node.getVariable().getName();
if (curDestination != null) {
if (!curDestination.equals(varName)) {
prepareMap();
mapSetMv.clear();
}
}
curDestination = varName;
super.visit(node);
}
@Override
public void visit(EndNode node) {
if (!mapSetMv.isEmpty()) {
prepareMap();
mapSetMv.clear();
}
super.visit(node);
}
/**
* Merges mergable GAPPSetMv to the first GAPPSetMv in mapSetMv
*/
private void prepareMap() {
for (LinkedList<GAPPSetMv> list : mapSetMv.values()) {
if (list.size() > 1) {
//merge setMv instructions into the first GAPPSetMv instruction
GAPPSetMv first = list.removeFirst();
for (GAPPSetMv cur : list) {
first.getSelectorsDest().addAll(cur.getSelectorsDest());
first.getSelectorsSrc().addAll(cur.getSelectorsSrc());
}
//and remove other instructions
toRemove.addAll(list);
}
}
}
@Override
public Object visitSetMv(GAPPSetMv gappSetMv, Object arg) {
if (gappSetMv.getDestination().getName().equals(curDestination)) {
String src = gappSetMv.getSource().getName();
if (!mapSetMv.containsKey(src)) {
mapSetMv.put(src, new LinkedList<GAPPSetMv>());
}
mapSetMv.get(src).add(gappSetMv);
}
return super.visitSetMv(gappSetMv, arg);
}
}