package wordlengthoptimization;
import datapath.graph.OperationVisitor;
import datapath.graph.operations.*;
import datapath.graph.operations.Add;
import datapath.graph.operations.ArcCos;
import datapath.graph.operations.BinaryOperation;
import datapath.graph.operations.BitwidthTransmogrify;
import datapath.graph.operations.ConstantOperation;
import datapath.graph.operations.ConstantShift;
import datapath.graph.operations.Cos;
import datapath.graph.operations.Divide;
import datapath.graph.operations.FromOuterLoop;
import datapath.graph.operations.HWInput;
import datapath.graph.operations.HWOutput;
import datapath.graph.operations.Less;
import datapath.graph.operations.Loop;
import datapath.graph.operations.LoopEnd;
import datapath.graph.operations.LoopInit;
import datapath.graph.operations.MemWrite;
import datapath.graph.operations.Multiplication;
import datapath.graph.operations.Mux;
import datapath.graph.operations.Negation;
import datapath.graph.operations.Nop;
import datapath.graph.operations.Operation;
import datapath.graph.operations.Predicate;
import datapath.graph.operations.Sin;
import datapath.graph.operations.SquareRoot;
import datapath.graph.operations.Subtraction;
import datapath.graph.operations.ToInnerLoop;
import datapath.graph.operations.ToOuterLoop;
import datapath.graph.operations.TopLevelInput;
import datapath.graph.operations.TypeConversion;
import datapath.graph.operations.VariableShift;
import datapath.graph.type.FixedPoint;
import datapath.graph.type.Type;
import java.util.HashMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import datapath.graph.operations.constValue.*;
import wordlengthoptimization.Util;
/**
* Recursive postorder visitor for the the ForwardProgagation.
*
* @author fs
*/
public class ForwardPropagationVisitor implements OperationVisitor {
/* stores for each operation the maximum and minimum value */
private HashMap<Operation, Double> maxValues = new HashMap();
private HashMap<Operation, Double> minValues = new HashMap();
public ForwardPropagationVisitor(HashMap<Operation, Double> statisticalMinValue,
HashMap<Operation, Double> statisticalMaxvalue ) {
maxValues = statisticalMaxvalue;
minValues = statisticalMinValue;
}
/* stores the number of required fractional bits for each operation */
private int changed = 0;
/**
* For debugging purpose, outputs the internal data of the visitor.
*/
public void outputStats() {
System.out.println("MaxValues: \n" + maxValues.toString());
System.out.println("MinValues: \n" + minValues.toString());
}
/**
*
* @return The number of nodes where the visitor changed the information
*/
public int getChanged() {
return changed;
}
/**
* Copies the Optimization informations (like min and maxvalue,
* precision, wordlength, ...) from one previous node to this node, without any
* specific change to them
* @param op Target operation, source is its predecessor. In case of multiple
* predecessors an exception is thrown
*/
private void copyInformation(Operation op) {
if (op.dependsOnOperations(true).size() != 1) {
throw new UnsupportedOperationException("More than one predecessor not supported in copyInformation");
}
Operation pred = op.dependsOnOperations(true).iterator().next();
op.setType((Type) pred.getType().clone());
minValues.put(op, minValues.get(pred));
maxValues.put(op, maxValues.get(pred));
}
@Override
public void visit(ConstantOperation op) {
double value = 0;
assert op.getValue() instanceof FloatValue || op.getValue() instanceof FixedPointValue;
if(op.getValue() instanceof FloatValue) {
value = (double)((FloatValue)op.getValue()).getValue();
}
if(op.getValue() instanceof FixedPointValue) {
value = (double)((FixedPointValue)op.getValue()).getValue();
}
long frac = Double.doubleToLongBits(value - Math.rint(value)) & 0x000fffffffffffffL;
//int prec = 65 - Long.numberOfLeadingZeros(frac);
int prec = Util.bitsRequiredForFraction(op.toString());
// in case of small values the exponent of value the fractional part could still be < 0
int exp = Math.getExponent(value-Math.rint(value)) + 1023;
if (exp < 0)
prec -= exp;
//minValues.put(op, value);
//maxValues.put(op, value);
op.setType(new FixedPoint(Util.bitsRequired(value, value)+prec, prec, value < 0));
}
@Override
public void visit(Add op) {
double min, max;
min = minValues.get(op.getLhs()) + minValues.get(op.getRhs());
max = maxValues.get(op.getLhs()) + maxValues.get(op.getRhs());
//minValues.put(op, min);
//maxValues.put(op, max);
min = minValues.get(op);
max = maxValues.get(op);
FixedPoint fpl = (FixedPoint) op.getLhs().getType();
FixedPoint fpr = (FixedPoint) op.getRhs().getType();
int prec = Math.max(fpl.getFractionlength(), fpr.getFractionlength());
op.setType(new FixedPoint(Util.bitsRequired(min, max) + prec, prec, min < 0));
}
@Override
public void visit(MemWrite op) {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public void visit(Less op) {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public void visit(FromOuterLoop op) {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public void visit(ToInnerLoop op) {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public void visit(HWInput op) {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public void visit(VariableShift op) {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public void visit(Loop op) {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public void visit(Nop op) {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public void visit(ToOuterLoop op) {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public void visit(Negation op) {
Operation pred = op.getData();
double minValue = -maxValues.get(pred);
double maxValue = -minValues.get(pred);
//minValues.put(op, minValue);
//maxValues.put(op, maxValue);
int prec = ((FixedPoint) pred.getType()).getFractionlength();
op.setType(new FixedPoint(Util.bitsRequired(minValue, maxValue) +prec, prec, minValue < 0.0));
}
@Override
public void visit(LoopEnd op) {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public void visit(LoopInit op) {
// do nothing
}
@Override
public void visit(HWOutput op) {
copyInformation(op);
}
@Override
public void visit(TopLevelInput op) {
if (op.getType() == null) {
op.setType(new FixedPoint(32, 16, true));
}
//minValues.put(op, op.getType().getMinValue());
//maxValues.put(op, op.getType().getMaxValue());
}
@Override
public void visit(Multiplication op) {
double min, max;
double v1, v2, v3, v4;
/* because of signedness we can not just multiply the min (max)
* values to get the resulting min (max) value */
v1 = maxValues.get(op.getLhs()) * maxValues.get(op.getRhs());
v2 = maxValues.get(op.getLhs()) * minValues.get(op.getRhs());
v3 = minValues.get(op.getLhs()) * maxValues.get(op.getRhs());
v4 = minValues.get(op.getLhs()) * minValues.get(op.getRhs());
min = Math.min(v1, Math.min(v2, Math.min(v3, v4)));
max = Math.max(v1, Math.max(v2, Math.max(v3, v4)));
min = minValues.get(op);
max = maxValues.get(op);
//minValues.put(op, min);
//maxValues.put(op, max);
FixedPoint fpl = (FixedPoint) op.getLhs().getType();
FixedPoint fpr = (FixedPoint) op.getRhs().getType();
int prec = Math.min(24,fpl.getFractionlength() +fpr.getFractionlength());
//int prec = Math.max(fpl.getFractionlength(), fpr.getFractionlength()) + 2;
op.setType(new FixedPoint(Util.bitsRequired(min, max) + prec, prec, min < 0));
}
@Override
public void visit(Subtraction op) {
double min, max;
min = minValues.get(op.getLhs()) - maxValues.get(op.getRhs());
max = maxValues.get(op.getLhs()) - minValues.get(op.getRhs());
min = minValues.get(op);
max = maxValues.get(op);
//minValues.put(op, min);
//maxValues.put(op, max);
FixedPoint fpl = (FixedPoint) op.getLhs().getType();
FixedPoint fpr = (FixedPoint) op.getRhs().getType();
int prec = Math.max(fpl.getFractionlength(), fpr.getFractionlength());
op.setType(new FixedPoint(Util.bitsRequired(min, max) + prec, prec, min < 0));
}
@Override
public void visit(Divide op) {
double min, max;
double v1,v2,v3,v4;
/* v1 = maxValues.get(op.getLhs()) / maxValues.get(op.getRhs());
v2 = maxValues.get(op.getLhs()) / minValues.get(op.getRhs());
v3 = minValues.get(op.getLhs()) / maxValues.get(op.getRhs());
v4 = minValues.get(op.getLhs()) / minValues.get(op.getRhs());
* */
v1 = maxValues.get(op.getLhs())*10;
v2 = minValues.get(op.getLhs());
v3 = maxValues.get(op.getRhs())*10;
v4 = minValues.get(op.getRhs());
min = Math.min(v1, Math.min(v2, Math.min(v3, v4)));
max = Math.max(v1, Math.max(v2, Math.max(v3, v4)));
min = minValues.get(op);
max = maxValues.get(op);
/* special treatment when we find that it is a normalization
* atm it is recognized by the variable name,
* better would be, to flag when a value results from abs() call,
* and we check it here */
if (op.isNormalization()) {
min = 0.0;
max = 1.0;
}
//minValues.put(op, min);
//maxValues.put(op, max);
FixedPoint fpl = (FixedPoint) op.getLhs().getType();
FixedPoint fpr = (FixedPoint) op.getRhs().getType();
int prec = Math.max(fpl.getFractionlength(), fpr.getFractionlength());
if (op.isNormalization()) {
prec = fpl.getFractionlength();
}
op.setType(new FixedPoint(32, prec, fpl.isSigned() || fpr.isSigned()));
}
@Override
public void visit(Sin op) {
double min, max;
min = -1.0;
max = 1.0;
minValues.put(op, min);
maxValues.put(op, max);
FixedPoint inputType = (FixedPoint) op.getData().getType();
op.setType(new FixedPoint(Util.bitsRequired(min, max), inputType.getFractionlength(), true));
}
@Override
public void visit(Cos op) {
double min, max;
min = -1.0;
max = 1.0;
minValues.put(op, min);
maxValues.put(op, max);
FixedPoint inputType = (FixedPoint) op.getData().getType();
op.setType(new FixedPoint(Util.bitsRequired(min, max), inputType.getFractionlength(), true));
}
@Override
public void visit(Operation op) {
throw new UnsupportedOperationException("Not supported yet." + op.getClass().toString());
}
@Override
public void visit(BinaryOperation op) {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public void visit(Mux op) {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public void visit(ConstantShift op) {
copyInformation(op);
}
@Override
public void visit(Absolut op) {
double min, max;
min = 0.0;
max = Math.max(Math.abs(maxValues.get(op.getData())),Math.abs(minValues.get(op.getData())));
//minValues.put(op, min);
//maxValues.put(op, max);
FixedPoint inputType = (FixedPoint) op.getData().getType();
int prec = inputType.getFractionlength();
op.setType(new FixedPoint(Util.bitsRequired(min, max) + prec, prec , false));
}
@Override
public void visit(ArcCos op) {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public void visit(SquareRoot op) {
double min, max;
min = 0.0;
max = Math.sqrt(maxValues.get(op.getData()));
//minValues.put(op, min);
//maxValues.put(op, max);
FixedPoint fp = (FixedPoint) op.getData().getType();
/* half as many frac bits, we round up, because in ShiftInserter
* an additonal left shift is performed to make the number of bits of the
* input even */
int prec = (fp.getFractionlength() +1 )/ 2;
op.setType(new FixedPoint(Math.min(32, Util.bitsRequired(min, max) + prec), prec, false));
}
@Override
public void visit(BitwidthTransmogrify op) {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public void visit(Predicate op) {
// do nothing
}
@Override
public void visit(TypeConversion op) {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public void visit(ConstantMultiplication op) {
visit((Multiplication)op);
}
}