//-----------------------------------------------------------------------------
//
// Copyright (C) Microsoft Corporation. All Rights Reserved.
//
//-----------------------------------------------------------------------------
using Microsoft.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][Reads(ReadsAttribute.Reads.Owned)]
public override System.Collections.Generic.ICollection! FreeVariables()
{
return (!) (new System.Collections.Generic.List()).AsReadOnly();
}
public override Element! Clone()
{
if (this.IsConstant)
return new Elt(constantValue);
else
return new Elt(domainValue);
}
}
readonly IIntExprFactory! factory;
public ConstantLattice(IIntExprFactory! factory)
{
this.factory = factory;
// base();
}
public override Element! Top
{
get { return new Elt(Value.Top); }
}
public override Element! Bottom
{
get { return new Elt(Value.Bottom); }
}
public override bool IsTop (Element! element)
{
Elt e = (Elt)element;
return e.domainValue == Value.Top;
}
public override bool IsBottom (Element! element)
{
Elt e = (Elt)element;
return e.domainValue == Value.Bottom;
}
public override Element! NontrivialJoin (Element! first, Element! second)
{
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)
{
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)
{
return Join(first,second);
}
protected override bool AtMost (Element! first, Element! second) // this <= that
{
Elt a = (Elt)first;
Elt b = (Elt)second;
return a.Constant.Equals(b.Constant);
}
public override IExpr! ToPredicate(IVariable! var, Element! element) {
return factory.Eq(var, (!)GetFoldExpr(element));
}
public override IExpr GetFoldExpr(Element! element) {
Elt e = (Elt)element;
assert e.domainValue == Value.Constant;
return factory.Const(e.constantValue);
}
public override bool Understands(IFunctionSymbol! f, IList/**/! args) {
return f.Equals(Microsoft.AbstractInterpretationFramework.Value.Eq);
}
public override Element! EvaluatePredicate(IExpr! e) {
IFunApp nary = e as IFunApp;
if (nary != null) {
if (nary.FunctionSymbol.Equals(Microsoft.AbstractInterpretationFramework.Value.Eq)) {
IList/**/! args = nary.Arguments;
assert args.Count == 2;
IExpr! arg0 = (IExpr!)args[0];
IExpr! arg1 = (IExpr!)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)
{
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;
assert args.Count == 1;
IExpr! arg0 = (IExpr!)args[0];
if (Fold(arg0, out z)) {
z = z.Neg;
return true;
}
} else if (e.Arguments.Count == 2) {
IExpr! arg0 = (IExpr!)e.Arguments[0];
IExpr! arg1 = (IExpr!)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;
}
}
}