// Always safe to return Top public static Value Evaluate(Expr expr, Dictionary <string, Value> subst) { var vused = new VarsUsed(); vused.Visit(expr); // Make sure we have values of all variables except in-formals var informals = vused.Vars.Where(v => !subst.ContainsKey(v.Name)); if (informals.All(v => (v is Formal) && ((v as Formal).InComing))) { } else { return(Value.GetTop()); } if (vused.Vars.Any(v => subst.ContainsKey(v.Name) && subst[v.Name].ToSingletonVar() == null)) { return(GetTop()); } var vsubst = new Dictionary <string, Variable>(); subst.Keys.Iter(v => vsubst.Add(v, subst[v].ToSingletonVar())); var dup = new FixedDuplicator(); var ne = (new VarSubstituter(vsubst, new Dictionary <string, Variable>())).VisitExpr(dup.VisitExpr(expr)); return(Value.GetSingleton(ne)); }
private Implementation processImplementation(Implementation node) { varsRead = new VarsUsed(); // Gather the set of vars used foreach (var b in node.Blocks) { base.VisitBlock(b); } globalsRead.UnionWith(varsRead.globalsUsed); // Get rid of declarations (before variable slice adds new variables) var newvars = new List <Variable>(); foreach (Variable v in node.LocVars) { if (varsRead.localsUsed.Contains(v.Name)) { newvars.Add(v); } } node.LocVars = newvars; // Do VariableSlicing VariableSlicing slice = new VariableSlicing(new VarSet(new HashSet <string>(varsRead.localsUsed), node.Name), ltinfo, node); for (int i = 0; i < node.Blocks.Count; i++) { node.Blocks[i] = slice.VisitBlock(node.Blocks[i]); } varsRead = null; return(node); }
static HashSet <string> GetReadVars(Cmd cmd) { if (cmd is PredicateCmd) { var expr = (cmd as PredicateCmd).Expr; var vu = new VarsUsed(); vu.VisitExpr(expr); return(vu.localsUsed); } else if (cmd is AssignCmd) { var ret = new HashSet <string>(); var acmd = cmd as AssignCmd; foreach (var expr in acmd.Rhss) { var vu = new VarsUsed(); vu.VisitExpr(expr); vu.localsUsed.Iter(v => ret.Add(v)); } foreach (var lhs in acmd.Lhss) { if (lhs is MapAssignLhs) { var mlhs = lhs as MapAssignLhs; foreach (var expr in mlhs.Indexes) { var vu = new VarsUsed(); vu.VisitExpr(expr); vu.localsUsed.Iter(v => ret.Add(v)); } } } return(ret); } else if (cmd is CallCmd) { var ret = new HashSet <string>(); var ccmd = cmd as CallCmd; foreach (var expr in ccmd.Ins) { var vu = new VarsUsed(); vu.VisitExpr(expr); vu.localsUsed.Iter(v => ret.Add(v)); } return(ret); } else { Console.WriteLine("Unable to process cmd - neither predicate, nor assign or call"); throw new NotImplementedException(); } }
public Value Subst(Dictionary <string, Value> subst) { if (isTrue) { return(this); } var newc = new HashSet <int>(constants); var newv = new HashSet <Variable>(); var newe = new HashSet <Expr>(); foreach (var v in vars) { Debug.Assert(subst.ContainsKey(v.Name)); if (subst[v.Name].isTrue) { return(GetTop()); } newc.UnionWith(subst[v.Name].constants); newv.UnionWith(subst[v.Name].vars); newe.UnionWith(subst[v.Name].constExprs); } foreach (var e in constExprs) { var vused = new VarsUsed(); vused.VisitExpr(e); Debug.Assert(vused.varsUsed.All(v => subst.ContainsKey(v))); if (vused.varsUsed.Any(v => subst[v].ToSingletonVar() == null)) { return(GetTop()); } var vsubst = new Dictionary <string, Variable>(); vused.varsUsed.Iter(v => vsubst.Add(v, subst[v].ToSingletonVar())); var dup = new FixedDuplicator(); var ne = (new VarSubstituter(vsubst, new Dictionary <string, Variable>())).VisitExpr(dup.VisitExpr(e)); newe.Add(ne); } newe = removeDuplicates(newe); if (newe.Count > maxExprsToTrack) { return(GetTop()); } var ret = new Value(); ret.vars = newv; ret.constants = newc; ret.constExprs = newe; ret.isTrue = false; return(ret); }
public UnReadVarEliminator(bool onlyLocals) { this.onlyLocals = onlyLocals; varsRead = null; globalsRead = null; ltinfo = new ModifyTrans(); gtinfo = new ModifyTrans(); sliceGlobals = null; }
public void compile(Implementation impl) { var ensures = impl.Proc.Ensures; var requires = impl.Proc.Requires; impl.Proc.Ensures = new List <Ensures>(); impl.Proc.Requires = new List <Requires>(); var reqCmds = new List <Cmd>(); var ensCmds = new List <Cmd>(); var newLocs = new List <Variable>(); var substOld = new SubstOldVars(); foreach (Ensures e in ensures) { Debug.Assert(e.Free); var expr = substOld.VisitExpr(e.Condition); ensCmds.Add(new AssumeCmd(Token.NoToken, expr, e.Attributes)); } foreach (Requires r in requires) { Debug.Assert(r.Free); var vu = new VarsUsed(); vu.VisitRequires(r); Debug.Assert(vu.oldVarsUsed.Count == 0); reqCmds.Add(new AssumeCmd(Token.NoToken, r.Condition, r.Attributes)); } reqCmds.AddRange(substOld.initLocVars); substOld.varMap.Values.Iter(lv => newLocs.Add(lv)); impl.LocVars.AddRange(newLocs); reqCmds.AddRange(impl.Blocks[0].Cmds); impl.Blocks[0].Cmds = reqCmds; foreach (var blk in impl.Blocks) { var rc = blk.TransferCmd as ReturnCmd; if (rc == null) { continue; } blk.Cmds.AddRange(ensCmds); } }
// onlyGlobals is true means assume all locals are tracked // onlyGlobals is false means assume all globals are tracked private bool isTracked(Absy exp, string name) { VarsUsed uses = new VarsUsed(); uses.Visit(exp); if (onlyGlobals) { return(trackedVars.Contains(new VarSet(uses.globalsUsed, name))); } else { return(trackedVars.Contains(new VarSet(uses.localsUsed, name))); } }
// Globals may also be read in procedures (without implementation) private void processProcedure(Procedure node) { varsRead = new VarsUsed(); foreach (Requires re in node.Requires) { varsRead.Visit(re.Condition); } foreach (Ensures en in node.Ensures) { varsRead.Visit(en.Condition); } globalsRead.UnionWith(varsRead.globalsUsed); }
// One cannot use "old" versions of shared globals private static void checkOld(Implementation impl) { VarsUsed used = new VarsUsed(); foreach (var blk in impl.Blocks) { foreach (Cmd cmd in blk.Cmds) { used.reset(); used.Visit(cmd); if (used.oldVarsUsed.Any()) { cmd.Emit(new TokenTextWriter(Console.Out), 0); throw new InvalidInput("Command has an \"old\" variable"); } } } }
public static Value GetSingleton(Expr e) { var vused = new VarsUsed(); vused.Visit(e); // An expr can only mention in-formals (TODO: and Constants) if (vused.Vars.Any(v => !(v is Formal))) { return(GetTop()); } if (vused.Vars.OfType <Formal>().Any(f => !f.InComing)) { return(GetTop()); } var ret = new Value(); ret.constExprs.Add(e); return(ret); }
// Mark "slic" assume statements // Mark "indirect" call assume statements public static void sdvAnnotateDefectTrace(Program trace, HashSet <string> slicVars, bool addSlicAnnotations = true) { //var slicVars = new HashSet<string>(config.trackedVars); //slicVars.Remove("alloc"); var isSlicExpr = new Predicate <Expr>(expr => { var vused = new VarsUsed(); vused.VisitExpr(expr); if (vused.varsUsed.Any(v => slicVars.Contains(v))) { return(true); } return(false); }); var isSlicAssume = new Func <AssumeCmd, Implementation, bool>((ac, impl) => { if (impl.Name.Contains("SLIC_") || impl.Name.Contains("sdv_")) { return(true); } if (isSlicExpr(ac.Expr)) { return(true); } return(false); }); var tagAssume = new Action <AssumeCmd, Implementation>((ac, impl) => { if (isSlicAssume(ac, impl)) { ac.Attributes = new QKeyValue(Token.NoToken, "slic", new List <object>(), ac.Attributes); } }); foreach (var impl in trace.TopLevelDeclarations .OfType <Implementation>()) { if (addSlicAnnotations) { // Insert "slic" annotation impl.Blocks.Iter(blk => blk.Cmds.OfType <AssumeCmd>() .Iter(cmd => tagAssume(cmd, impl))); } // Insert "indirect" annotation foreach (var blk in impl.Blocks) { for (int i = 0; i < blk.Cmds.Count - 1; i++) { var c1 = blk.Cmds[i] as AssumeCmd; var c2 = blk.Cmds[i + 1] as AssumeCmd; if (c1 == null || c2 == null) { continue; } if (!QKeyValue.FindBoolAttribute(c1.Attributes, "IndirectCall")) { continue; } c2.Attributes = new QKeyValue(Token.NoToken, "indirect", new List <object>(), c2.Attributes); } } } // Mark malloc foreach (var impl in trace.TopLevelDeclarations .OfType <Implementation>()) { foreach (var blk in impl.Blocks) { var ncmds = new List <Cmd>(); foreach (Cmd cmd in blk.Cmds) { ncmds.Add(cmd); var ccmd = cmd as CallCmd; if (ccmd == null || !ccmd.callee.Contains("HAVOC_malloc")) { continue; } var ac = new AssertCmd(Token.NoToken, Expr.True); ac.Attributes = new QKeyValue(Token.NoToken, "malloc", new List <object>(), null); ncmds.Add(ac); } blk.Cmds = ncmds; } } }
// -- There should be no ensures and requires on shared globals // -- For ensures and requires on non-shared globals, they should be "free" // -- One cannot use "old" versions of shared globals private static void checkProc(Procedure proc, HashSet <string> procsWithImpl, HashSet <string> procsNotCalled) { VarsUsed used = new VarsUsed(); foreach (Requires re in proc.Requires) { used.reset(); used.Visit(re.Condition); if (used.globalsUsed.Any(v => LanguageSemantics.isShared(v))) { re.Emit(new TokenTextWriter(Console.Out), 0); throw new InvalidInput("Requires has a shared global"); } if (used.oldVarsUsed.Any(v => LanguageSemantics.isShared(v))) { re.Emit(new TokenTextWriter(Console.Out), 0); throw new InvalidInput("Requires has an \"old\" shared global"); } if (used.globalsUsed.Count == 0) { continue; } // We dont care about requires on pros that are not called if (procsNotCalled.Contains(proc.Name)) { continue; } if (re.Free == false) { re.Emit(new TokenTextWriter(Console.Out), 0); throw new InvalidInput("A non-free requires has a non-shared global (not yet supported)"); } } foreach (Ensures re in proc.Ensures) { used.reset(); used.Visit(re.Condition); if (used.globalsUsed.Any(v => LanguageSemantics.isShared(v))) { re.Emit(new TokenTextWriter(Console.Out), 0); throw new InvalidInput("Ensures has a shared global"); } if (used.oldVarsUsed.Any(v => LanguageSemantics.isShared(v))) { re.Emit(new TokenTextWriter(Console.Out), 0); throw new InvalidInput("Ensures has an \"old\" shared global"); } /* * if (used.globalsUsed.Count == 0) * { * continue; * } */ // "Ensures" in procs without implementation are considered free if (re.Free == false && procsWithImpl.Contains(proc.Name)) { re.Emit(new TokenTextWriter(Console.Out), 0); throw new InvalidInput("A non-free ensures is not yet supported"); } } }
// deprecated public static string FindAnnotationsOld(string predicate) { var expr = ToExpr(predicate); var ret = ""; // Get variables used in the expr var variables = new HashSet <Variable>(); var vu = new VarsUsed(); vu.VisitExpr(expr); variables = vu.Vars; // yogi_error variable present? var err = variables.Where(v => v.Name == "yogi_error").FirstOrDefault(); Expr pre = Expr.True; if (err != null) { pre = Expr.Eq(new OldExpr(Token.NoToken, Expr.Ident(err)), Expr.Literal(0)); } foreach (var v in variables) { Expr nmod = Expr.Eq(new OldExpr(Token.NoToken, Expr.Ident(v)), Expr.Ident(v)); nmod = Expr.And(nmod, pre); var check = Expr.And(nmod, Expr.Not(expr)); if (CheckIfUnsat(check)) { ret += string.Format(" {{:mustmod \"{0}\" }}", v); continue; } if (err != null && v.Name == err.Name) { continue; } var rand = new System.Random(); var rvalues = new HashSet <int>(); for (int i = 0; i < 3; i++) { rvalues.Add(rand.Next(0, 10)); } for (int i = 0; i < 3; i++) { rvalues.Add(rand.Next(-10, 0)); } foreach (var val in rvalues) { //Console.WriteLine("Trying {0}", val); check = Expr.And(nmod, Expr.Eq(new OldExpr(Token.NoToken, Expr.Ident(v)), Expr.Literal(val))); check = Expr.And(check, expr); if (CheckIfUnsat(check)) { ret += string.Format(" {{:mustmod \"{0}\" }}", v); break; } } } return(ret); }