//-----------------------------------------------------------------------------
//
// Copyright (C) Microsoft Corporation. All Rights Reserved.
//
//-----------------------------------------------------------------------------
using System.Diagnostics.Contracts;
namespace Microsoft.AbstractInterpretationFramework {
using System.Collections;
using System.Diagnostics;
//using System.Compiler.Analysis;
using Microsoft.Basetypes;
///
/// Represents an invariant over constant variable assignments.
///
public class ConstantLattice : MicroLattice {
enum Value {
Top,
Bottom,
Constant
}
private class Elt : Element {
public Value domainValue;
public BigNum constantValue; // valid iff domainValue == Value.Constant
public Elt(Value v) {
this.domainValue = v;
}
public Elt(BigNum i) {
this.domainValue = Value.Constant;
this.constantValue = i;
}
public bool IsConstant {
get {
return this.domainValue == Value.Constant;
}
}
public BigNum Constant {
get {
return this.constantValue;
}
} // only when IsConstant
[Pure]
public override System.Collections.Generic.ICollection/*!*/ FreeVariables() {
Contract.Ensures(cce.NonNullElements(Contract.Result>()));
return cce.NonNull(new System.Collections.Generic.List()).AsReadOnly();
}
public override Element/*!*/ Clone() {
Contract.Ensures(Contract.Result() != null);
if (this.IsConstant)
return new Elt(constantValue);
else
return new Elt(domainValue);
}
}
readonly IIntExprFactory/*!*/ factory;
[ContractInvariantMethod]
void ObjectInvariant() {
Contract.Invariant(factory != null);
}
public ConstantLattice(IIntExprFactory/*!*/ factory) {
Contract.Requires(factory != null);
this.factory = factory;
// base();
}
public override Element/*!*/ Top {
get {
Contract.Ensures(Contract.Result() != null);
return new Elt(Value.Top);
}
}
public override Element/*!*/ Bottom {
get {
Contract.Ensures(Contract.Result() != null);
return new Elt(Value.Bottom);
}
}
public override bool IsTop(Element/*!*/ element) {
//Contract.Requires(element != null);
Elt e = (Elt)element;
return e.domainValue == Value.Top;
}
public override bool IsBottom(Element/*!*/ element) {
//Contract.Requires(element != null);
Elt e = (Elt)element;
return e.domainValue == Value.Bottom;
}
public override Element/*!*/ NontrivialJoin(Element/*!*/ first, Element/*!*/ second) {
//Contract.Requires(second != null);
//Contract.Requires(first != null);
Contract.Ensures(Contract.Result() != null);
Elt a = (Elt)first;
Elt b = (Elt)second;
Debug.Assert(a.domainValue == Value.Constant && b.domainValue == Value.Constant);
return (a.constantValue.Equals(b.constantValue)) ? a : (Elt)Top;
}
public override Element/*!*/ NontrivialMeet(Element/*!*/ first, Element/*!*/ second) {
//Contract.Requires(second != null);
//Contract.Requires(first != null);
Contract.Ensures(Contract.Result() != null);
Elt a = (Elt)first;
Elt b = (Elt)second;
Debug.Assert(a.domainValue == Value.Constant && b.domainValue == Value.Constant);
return (a.constantValue.Equals(b.constantValue)) ? a : (Elt)Bottom;
}
public override Element/*!*/ Widen(Element/*!*/ first, Element/*!*/ second) {
//Contract.Requires(second != null);
//Contract.Requires(first != null);
Contract.Ensures(Contract.Result() != null);
return Join(first, second);
}
protected override bool AtMost(Element/*!*/ first, Element/*!*/ second) // this <= that
{
//Contract.Requires(first!= null);
//Contract.Requires(second != null);
Elt a = (Elt)first;
Elt b = (Elt)second;
return a.Constant.Equals(b.Constant);
}
public override IExpr/*!*/ ToPredicate(IVariable/*!*/ var, Element/*!*/ element) {
//Contract.Requires(element != null);
//Contract.Requires(var != null);
Contract.Ensures(Contract.Result() != null);
return factory.Eq(var, cce.NonNull(GetFoldExpr(element)));
}
public override IExpr GetFoldExpr(Element/*!*/ element) {
//Contract.Requires(element != null);
Elt e = (Elt)element;
Contract.Assert(e.domainValue == Value.Constant);
return factory.Const(e.constantValue);
}
public override bool Understands(IFunctionSymbol/*!*/ f, IList/**//*!*/ args) {
//Contract.Requires(args != null);
//Contract.Requires(f != null);
return f.Equals(Microsoft.AbstractInterpretationFramework.Value.Eq);
}
public override Element/*!*/ EvaluatePredicate(IExpr/*!*/ e) {
//Contract.Requires(e != null);
Contract.Ensures(Contract.Result() != null);
IFunApp nary = e as IFunApp;
if (nary != null) {
if (nary.FunctionSymbol.Equals(Microsoft.AbstractInterpretationFramework.Value.Eq)) {
IList/**//*!*/ args = nary.Arguments;
Contract.Assert(args != null);
Contract.Assert(args.Count == 2);
IExpr/*!*/ arg0 = (IExpr/*!*/)cce.NonNull(args[0]);
IExpr/*!*/ arg1 = (IExpr/*!*/)cce.NonNull(args[1]);
// Look for "x == const" or "const == x".
try {
if (arg0 is IVariable) {
BigNum z;
if (Fold(arg1, out z)) {
return new Elt(z);
}
} else if (arg1 is IVariable) {
BigNum z;
if (Fold(arg0, out z)) {
return new Elt(z);
}
}
} catch (System.ArithmeticException) {
// fall through and return Top. (Note, an alternative design may
// consider returning Bottom.)
}
}
}
return Top;
}
///
/// Returns true if "expr" represents a constant integer expressions, in which case
/// "z" returns as that integer. Otherwise, returns false, in which case "z" should
/// not be used by the caller.
///
/// This method throws an System.ArithmeticException in the event that folding the
/// constant expression results in an arithmetic overflow or division by zero.
///
private bool Fold(IExpr/*!*/ expr, out BigNum z) {
Contract.Requires(expr != null);
IFunApp e = expr as IFunApp;
if (e == null) {
z = BigNum.ZERO;
return false;
}
if (e.FunctionSymbol is IntSymbol) {
z = ((IntSymbol)e.FunctionSymbol).Value;
return true;
} else if (e.FunctionSymbol.Equals(Int.Negate)) {
IList/**//*!*/ args = e.Arguments;
Contract.Assert(args != null);
Contract.Assert(args.Count == 1);
IExpr/*!*/ arg0 = (IExpr/*!*/)cce.NonNull(args[0]);
if (Fold(arg0, out z)) {
z = z.Neg;
return true;
}
} else if (e.Arguments.Count == 2) {
IExpr/*!*/ arg0 = (IExpr/*!*/)cce.NonNull(e.Arguments[0]);
IExpr/*!*/ arg1 = (IExpr/*!*/)cce.NonNull(e.Arguments[1]);
BigNum z0, z1;
if (Fold(arg0, out z0) && Fold(arg1, out z1)) {
if (e.FunctionSymbol.Equals(Int.Add)) {
z = z0 + z1;
} else if (e.FunctionSymbol.Equals(Int.Sub)) {
z = z0 - z1;
} else if (e.FunctionSymbol.Equals(Int.Mul)) {
z = z0 * z1;
} else if (e.FunctionSymbol.Equals(Int.Div)) {
z = z0 / z1;
} else if (e.FunctionSymbol.Equals(Int.Mod)) {
z = z0 % z1;
} else {
z = BigNum.ZERO;
return false;
}
return true;
}
}
z = BigNum.ZERO;
return false;
}
}
}