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 ForwardPropagationVisitorNewTypeCast 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 ForwardPropagationVisitorNewTypeCast(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);
max = maxValues.get(op);
FixedPoint fpl = (FixedPoint) op.getLhs().getType();
FixedPoint fpr = (FixedPoint) op.getRhs().getType();
boolean signed = fpl.isSigned() || fpr.isSigned();
int prec = Math.max(fpl.getFractionlength(), fpr.getFractionlength());
int intfpl = fpl.getIntBits();
int intfpr = fpr.getIntBits();
if (signed) {
intfpl++;
intfpr++;
}
int intbitsize = Math.max(intfpl, Math.max(intfpr, Util.bitsRequired(min, max)));
op.setType(new FixedPoint(intbitsize + prec + 1, prec, signed));
}
@Override
public void visit(Negation op) {
Operation pred = op.getData();
double minValue = -maxValues.get(pred);
double maxValue = -minValues.get(pred);
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));
}
}
@Override
public void visit(Multiplication op) {
double min, max;
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 = fpl.getFractionlength() +fpr.getFractionlength();
boolean signed = (min < 0.0) || fpl.isSigned() || fpr.isSigned();
int bitsize = Util.bitsRequired(min, max);
if (min >= 0 && signed)
bitsize++;
//int prec = Math.max(fpl.getFractionlength(), fpr.getFractionlength()) + 2;
op.setType( new FixedPoint(bitsize + prec, prec, signed));
}
@Override
public void visit(Subtraction op) {
double min, 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());
int intfpl = fpl.getIntBits() + 1;
int intfpr = fpr.getIntBits() + 1;
int intbitsize = Math.max(intfpl, Math.max(intfpr, Util.bitsRequired(min, max)));
op.setType(new FixedPoint(intbitsize + prec +1, prec, true));
}
@Override
public void visit(Divide op) {
double min, max;
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 = -1.0;
max = 1.0;
}
FixedPoint fpl = (FixedPoint) op.getLhs().getType();
FixedPoint fpr = (FixedPoint) op.getRhs().getType();
// hardcoded 32
int prec = 62; //Math.max(fpl.getFractionlength(), fpr.getFractionlength());
// if (op.isNormalization()) {
// prec = fpl.getFractionlength();
//
// }
int bitsize = Util.bitsRequired(min, max) + 1 + prec;
boolean signed = true; //min < 0.0 || fpl.isSigned() || fpr.isSigned();
/* in case the result is always > 0, but the divider is signed,
the additional sign bit has to taken into account */
if (signed || ! (min < 0.0)) {
bitsize++;
}
op.setType(new FixedPoint(bitsize , prec, signed));
}
@Override
public void visit(Sin op) {
double min, max;
min = -1.0;
max = 1.0;
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;
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) {
FixedPoint inputType = (FixedPoint) op.getData().getType();
FixedPoint resultType = null;
int totalBitsize = inputType.getBitsize();
int prec = inputType.getFractionlength();
switch (op.getMode()) {
case Left:
case LeftRotate:
prec = prec - op.getShiftAmount();
if (prec < 0) {
totalBitsize += -prec;
prec = 0;
}
op.setMode(ShiftMode.ZeroShiftLeft);
break;
case Right:
case SignedRight:
case RightRotate:
prec = prec + op.getShiftAmount();
if (prec > totalBitsize || (inputType.isSigned() && prec >= totalBitsize)) {
totalBitsize = prec;
if (inputType.isSigned()) {
totalBitsize++;
}
}
op.setMode(ShiftMode.ZeroShiftRight);
break;
default:
assert (false);
}
resultType = new FixedPoint(totalBitsize, prec, inputType.isSigned());
op.setType(resultType);
}
@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())));
FixedPoint inputType = (FixedPoint) op.getData().getType();
int prec = inputType.getFractionlength();
op.setType(new FixedPoint(Util.bitsRequired(min, max) + prec +1, prec , true));
}
@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()));
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 = Math.min(32, (fp.getFractionlength() + 1 )/ 2);
op.setType(new FixedPoint(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(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(ConstantMultiplication op) {
visit((Multiplication)op);
}
}