package de.gaalop.algebra;
import de.gaalop.cfg.*;
import de.gaalop.dfg.Expression;
import de.gaalop.dfg.FloatConstant;
import de.gaalop.dfg.MacroCall;
import de.gaalop.dfg.MathFunction;
import de.gaalop.dfg.MathFunctionCall;
import de.gaalop.dfg.Variable;
import de.gaalop.visitors.DFGTraversalVisitor;
import de.gaalop.visitors.ReplaceVisitor;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
/**
* Inlines the macros in a ControlFlowGraph
* @author Christian Steinmetz
*/
public class Inliner extends EmptyControlFlowVisitor {
private int count = 0;
private HashMap<StringIntContainer, Macro> macros;
private ControlFlowGraph graph;
private ColorNode currentColorNode = null;
private boolean containsMacroCall(Expression e) {
final LinkedList<MacroCall> calls = new LinkedList<MacroCall>();
e.accept(new DFGTraversalVisitor() {
@Override
public void visit(MacroCall node) {
calls.add(node);
}
});
return !calls.isEmpty();
}
private Inliner(HashMap<StringIntContainer, Macro> macros, ControlFlowGraph graph) { //private constructor for making the usage of the static methods mandatory
this.macros = macros;
this.graph = graph;
}
public static void inline(ControlFlowGraph graph, HashMap<StringIntContainer, Macro> macros) {
Inliner inliner = new Inliner(macros, graph);
while (!inliner.error && MacroCallCounter.countMacroCallsInGraph(graph)>0)
graph.accept(inliner);
}
@Override
public void visit(ColorNode node) {
curNode = node;
//make all non-variable arguments to variables
Expression c = node.getR();
if (!((c instanceof Variable) || (c instanceof FloatConstant))) {
Variable newVariable = createNewVariable();
AssignmentNode assignmentNode = new AssignmentNode(graph, newVariable, c);
curNode.insertBefore(assignmentNode);
StoreResultNode storeNode = new StoreResultNode(graph, newVariable);
curNode.insertBefore(storeNode);
node.setR(newVariable);
}
c = node.getG();
if (!((c instanceof Variable) || (c instanceof FloatConstant))) {
Variable newVariable = createNewVariable();
AssignmentNode assignmentNode = new AssignmentNode(graph, newVariable, c);
curNode.insertBefore(assignmentNode);
StoreResultNode storeNode = new StoreResultNode(graph, newVariable);
curNode.insertBefore(storeNode);
node.setG(newVariable);
}
c = node.getB();
if (!((c instanceof Variable) || (c instanceof FloatConstant))) {
Variable newVariable = createNewVariable();
AssignmentNode assignmentNode = new AssignmentNode(graph, newVariable, c);
curNode.insertBefore(assignmentNode);
StoreResultNode storeNode = new StoreResultNode(graph, newVariable);
curNode.insertBefore(storeNode);
node.setB(newVariable);
}
c = node.getAlpha();
if (!((c instanceof Variable) || (c instanceof FloatConstant))) {
Variable newVariable = createNewVariable();
AssignmentNode assignmentNode = new AssignmentNode(graph, newVariable, c);
curNode.insertBefore(assignmentNode);
StoreResultNode storeNode = new StoreResultNode(graph, newVariable);
curNode.insertBefore(storeNode);
node.setAlpha(newVariable);
}
currentColorNode = node;
super.visit(node);
}
private Inliner() {
}
private SequentialNode curNode;
private boolean error = false;
@Override
public void visit(AssignmentNode node) {
curNode = node;
while (containsMacroCall(node.getValue()) && !error) {
replacer.result = null;
node.getValue().accept(replacer);
if (replacer.result != null)
node.setValue(replacer.result);
}
super.visit(node);
}
@Override
public void visit(ExpressionStatement node) {
curNode = node;
replacer.result = null;
delete = false;
node.getExpression().accept(replacer);
boolean del = delete;
Expression result = replacer.result;
if (result != null)
node.setExpression(result);
super.visit(node);
if (del)
graph.removeNode(node);
}
private boolean delete;
//TODO chs (optional) macros are case sensitive, math functions not!
private ReplaceVisitor replacer = new ReplaceVisitor() {
@Override
public void visit(MacroCall node) {
String macroCallName = node.getName();
//check if this macro call is a MathFunction
for (MathFunction f: MathFunction.values()) {
if (f.name().toLowerCase().equals(macroCallName.toLowerCase())) {
// it is a MathFunction
result = new MathFunctionCall(node.getArguments().get(0), f);
return;
}
}
StringIntContainer container = new StringIntContainer(macroCallName, node.getArguments().size());
if (!macros.containsKey(container)) {
System.err.println("Macro "+macroCallName+" is not defined!");
error = true; //escape endless loop!
result = null;
delete = true;
graph.unknownMacros.add(new UnknownMacroCall(node, currentColorNode));
//make all non-variable arguments to variables
ArrayList<Expression> newArgs = new ArrayList<Expression>(node.getArguments().size());
for (Expression arg: node.getArguments()) {
if (!((arg instanceof Variable) || (arg instanceof FloatConstant))) {
Variable newVariable = createNewVariable();
AssignmentNode assignmentNode = new AssignmentNode(graph, newVariable, arg);
curNode.insertBefore(assignmentNode);
StoreResultNode storeNode = new StoreResultNode(graph, newVariable);
curNode.insertBefore(storeNode);
newArgs.add(newVariable);
} else
newArgs.add(arg);
}
node.setArgs(newArgs);
return;
}
Macro macro = macros.get(container);
HashMap<String, Expression> replaceMap = new HashMap<String, Expression>();
//fill replaceMap with macro call arguments
int index = 1;
for (Expression e: node.getArguments()) {
replaceMap.put("_P("+index+")", e);
index++;
}
//add replacements
for (SequentialNode sNode: macro.getBody()) {
if (sNode instanceof AssignmentNode) {
AssignmentNode assignmentNode = (AssignmentNode) sNode;
String name = assignmentNode.getVariable().getName();
if (!replaceMap.containsKey(name))
replaceMap.put(name, createNewVariable());
}
}
for (SequentialNode sNode: macro.getBody()) {
SequentialNode copySNode = sNode.copy();
//replace variables in copySNode
MacroVariablesCFGReplacer r = new MacroVariablesCFGReplacer(replaceMap);
copySNode.accept(r);
//
curNode.insertBefore(copySNode);
}
Expression copiedReturnVal = macro.getReturnValue().copy();
//replace variables in copiedReturnVal
MacroVariablesDFGReplacer d = new MacroVariablesDFGReplacer(replaceMap);
copiedReturnVal.accept(d);
//
result = copiedReturnVal;
}
};
private Variable createNewVariable() {
VariableCollector collector = new VariableCollector();
graph.accept(collector);
count++;
while (collector.getVariables().contains("macroUniqueName"+count))
count++;
return new Variable("macroUniqueName"+count);
}
}