Skip to content

Instantly share code, notes, and snippets.

@UplinkCoder
Last active August 29, 2015 14:07
Show Gist options
  • Save UplinkCoder/8dc304ffc75ad2a3de40 to your computer and use it in GitHub Desktop.
Save UplinkCoder/8dc304ffc75ad2a3de40 to your computer and use it in GitHub Desktop.
ValueRange Visitor
module d.semantic.valuerange;
import d.semantic.semantic;
import d.ir.type;
import d.ast.expression;
import d.ir.expression;
struct ValueRange {
double _min;
double _max;
bool isInRangeOf(ValueRange that) {
return (that._max>=_max && that._min<=_min);
}
bool isInRangeOf (TypeKind k) {
return isInRangeOf(rangeOf(k));
}
ValueRange opBinary (string op)(ValueRange rhs) {
static if (op=="-") {
return ValueRange(_min-rhs._max, _max-rhs._min);
} else static if (op=="+") {
return ValueRange(_min+rhs._min, _max+rhs._max);
} else
assert(0, "Not Implemented");
}
unittest {
assert(ValueRange(0,255)-ValueRange(128,128) == ValueRange(-128,127));
assert(ValueRange(3,3)+ValueRange(-5,2)==ValueRange(-2,5));
}
ValueRange merge (ValueRange rhs) {
import std.algorithm:max,min;
return ValueRange(min(_min, rhs._min), max(_max, rhs._max));
}
static ValueRange rangeOf(TypeKind t) {
if (t == TypeKind.Bool) {
return ValueRange(bool.min,bool.max);
} else if (t == TypeKind.Ubyte) {
return ValueRange (ubyte.min,ubyte.max);
} else if (t == TypeKind.Ushort) {
return ValueRange (ushort.min,ushort.max);
} else if (t == TypeKind.Uint) {
return ValueRange (uint.min,uint.max);
} else if (t == TypeKind.Ulong) {
return ValueRange (ulong.min,ulong.max);
} else if (t == TypeKind.Byte) {
return ValueRange (byte.min,byte.max);
} else if (t == TypeKind.Short) {
return ValueRange (short.min,short.max);
} else if (t == TypeKind.Int) {
return ValueRange (int.min,int.max);
} else if (t == TypeKind.Long) {
return ValueRange (long.min,cast(double)long.max);
}
assert(0,"Rangeof does not accept " ~ typeid(t).toString() );
}
}
struct ValueRangeVisitor {
SemanticPass pass;
this(SemanticPass pass)
{
this.pass = pass;
}
ValueRange visit(VariableExpression e) {
auto BType = peelAlias(e.type);
assert(typeid(BType.type) == typeid(BuiltinType));
return ValueRange.rangeOf((cast(BuiltinType) BType.type).kind);
}
ValueRange visit(AstBinaryExpression e) {
ValueRange lhs = visit(e.lhs);
ValueRange rhs = visit(e.rhs);
switch (e.op) with (BinaryOp) {
case Add : return lhs+rhs;
case Sub : return lhs-rhs;
default : assert(0, "BinaryOp " ~ e.toString(pass.context)~" not supported by ValueRangeVisitor" );
}
}
ValueRange visit(AstExpression e) {
return this.dispatch!(function ValueRange(AstExpression e) {
assert(0, "ValueRange " ~ typeid(e).toString() ~ " is unknown.");
})(e);
}
ValueRange visit(IntegerLiteral!false e) {
return ValueRange(e.value,e.value);
}
ValueRange visit(IntegerLiteral!true e) {
return ValueRange(e.value,e.value);
}
unittest {
import d.location;
import std.stdio;
auto il = new IntegerLiteral!false(Location.init,1,TypeKind.Int);
assert(ValueRangeVisitor().visit(il).isInRangeOf(TypeKind.Byte));
assert(ValueRangeVisitor().visit(il).isInRangeOf(TypeKind.Bool));
assert(ValueRangeVisitor().visit(new AstBinaryExpression(Location.init, BinaryOp.Sub, new IntegerLiteral!false(Location.init, 255, TypeKind.Uint),new IntegerLiteral!false(Location.init, 128, TypeKind.Int))).isInRangeOf(TypeKind.Byte));
assert(ValueRange.rangeOf(TypeKind.Ubyte).isInRangeOf(TypeKind.Short));
assert(!(ValueRange.rangeOf(TypeKind.Short).isInRangeOf(TypeKind.Byte)));
}
}
@deadalnix
Copy link

I don't think that it is the right approach. This need to be integrated with ExpressionVisitor (as there will be composition) and StatementVisitor (as it is control flow sensitive).

VRP is a tricky one. A simpler version of this problem is destructor insertion and/or unreachable statement.

@deadalnix
Copy link

Also, VRP struct should work for integers as well. Using float here will have cause issues. Right now, SDC do not support floating point at all.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment