PageRenderTime 38ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 1ms

/Source/Houdini/AbstractHoudini.cs

#
C# | 4609 lines | 3666 code | 693 blank | 250 comment | 715 complexity | e5add6417232b0ae9b3a8eaaf32279ed MD5 | raw file
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using Microsoft.Boogie;
  6. using Microsoft.Boogie.VCExprAST;
  7. using VC;
  8. using Outcome = VC.VCGen.Outcome;
  9. using Bpl = Microsoft.Boogie;
  10. using System.Diagnostics;
  11. using System.Diagnostics.Contracts;
  12. using Microsoft.Boogie.GraphUtil;
  13. namespace Microsoft.Boogie.Houdini {
  14. public class AbsHoudini
  15. {
  16. Dictionary<string, Function> existentialFunctions;
  17. Program program;
  18. Dictionary<string, Implementation> name2Impl;
  19. Dictionary<string, VCExpr> impl2VC;
  20. Dictionary<string, List<Tuple<string, Function, NAryExpr>>> impl2FuncCalls;
  21. // constant -> the naryexpr that it replaced
  22. Dictionary<string, NAryExpr> constant2FuncCall;
  23. // function -> its abstract value
  24. Dictionary<string, IAbstractDomain> function2Value;
  25. // impl -> functions assumed/asserted
  26. Dictionary<string, HashSet<string>> impl2functionsAsserted, impl2functionsAssumed;
  27. // funtions -> impls where assumed/asserted
  28. Dictionary<string, HashSet<string>> function2implAssumed, function2implAsserted;
  29. // impl -> handler, collector
  30. Dictionary<string, Tuple<ProverInterface.ErrorHandler, AbsHoudiniCounterexampleCollector>> impl2ErrorHandler;
  31. // Essentials: VCGen, Prover
  32. VCGen vcgen;
  33. ProverInterface prover;
  34. // Stats
  35. TimeSpan proverTime;
  36. int numProverQueries;
  37. public AbsHoudini(Program program, IAbstractDomain defaultElem)
  38. {
  39. this.program = program;
  40. this.impl2VC = new Dictionary<string, VCExpr>();
  41. this.impl2FuncCalls = new Dictionary<string, List<Tuple<string, Function, NAryExpr>>>();
  42. this.existentialFunctions = new Dictionary<string, Function>();
  43. this.name2Impl = new Dictionary<string, Implementation>();
  44. this.impl2functionsAsserted = new Dictionary<string, HashSet<string>>();
  45. this.impl2functionsAssumed = new Dictionary<string, HashSet<string>>();
  46. this.function2implAsserted = new Dictionary<string, HashSet<string>>();
  47. this.function2implAssumed = new Dictionary<string, HashSet<string>>();
  48. this.impl2ErrorHandler = new Dictionary<string, Tuple<ProverInterface.ErrorHandler, AbsHoudiniCounterexampleCollector>>();
  49. this.constant2FuncCall = new Dictionary<string, NAryExpr>();
  50. // Find the existential functions
  51. foreach (var func in program.Functions
  52. .Where(f => QKeyValue.FindBoolAttribute(f.Attributes, "existential")))
  53. existentialFunctions.Add(func.Name, func);
  54. this.function2Value = new Dictionary<string, IAbstractDomain>();
  55. foreach (var func in existentialFunctions.Values)
  56. {
  57. // Find if the function wishes to use a specific abstract domain
  58. var domain = QKeyValue.FindStringAttribute(func.Attributes, "absdomain");
  59. if (domain == null)
  60. {
  61. function2Value[func.Name] = defaultElem.Bottom();
  62. }
  63. else
  64. {
  65. function2Value[func.Name] = AbstractDomainFactory.GetInstance(domain);
  66. }
  67. }
  68. existentialFunctions.Keys.Iter(f => function2implAssumed.Add(f, new HashSet<string>()));
  69. existentialFunctions.Keys.Iter(f => function2implAsserted.Add(f, new HashSet<string>()));
  70. // type check
  71. existentialFunctions.Values.Iter(func =>
  72. {
  73. if (func.OutParams.Count != 1 || !func.OutParams[0].TypedIdent.Type.IsBool)
  74. throw new AbsHoudiniInternalError(string.Format("Existential function {0} must return bool", func.Name));
  75. if(func.Body != null)
  76. throw new AbsHoudiniInternalError(string.Format("Existential function {0} should not have a body", func.Name));
  77. var args = new List<Type>();
  78. func.InParams.Iter(v => args.Add(v.TypedIdent.Type));
  79. string msg = "";
  80. if (!function2Value[func.Name].TypeCheck(args, out msg))
  81. throw new AbsHoudiniInternalError("TypeError: " + msg);
  82. });
  83. //if (CommandLineOptions.Clo.ProverKillTime > 0)
  84. // CommandLineOptions.Clo.ProverOptions.Add(string.Format("TIME_LIMIT={0}", CommandLineOptions.Clo.ProverKillTime));
  85. Inline();
  86. this.vcgen = new VCGen(program, CommandLineOptions.Clo.SimplifyLogFilePath, CommandLineOptions.Clo.SimplifyLogFileAppend, new List<Checker>());
  87. this.prover = ProverInterface.CreateProver(program, CommandLineOptions.Clo.SimplifyLogFilePath, CommandLineOptions.Clo.SimplifyLogFileAppend, CommandLineOptions.Clo.ProverKillTime);
  88. this.proverTime = TimeSpan.Zero;
  89. this.numProverQueries = 0;
  90. program.Implementations
  91. .Where(impl => !impl.SkipVerification)
  92. .Iter(impl => name2Impl.Add(impl.Name, impl));
  93. // Let's do VC Gen (and also build dependencies)
  94. name2Impl.Values.Iter(GenVC);
  95. }
  96. public VCGenOutcome ComputeSummaries()
  97. {
  98. var overallOutcome = new VCGenOutcome(ProverInterface.Outcome.Valid, new List<Counterexample>());
  99. // Compute SCCs and determine a priority order for impls
  100. var Succ = new Dictionary<string, HashSet<string>>();
  101. var Pred = new Dictionary<string, HashSet<string>>();
  102. name2Impl.Keys.Iter(s => Succ[s] = new HashSet<string>());
  103. name2Impl.Keys.Iter(s => Pred[s] = new HashSet<string>());
  104. foreach(var impl in name2Impl.Keys) {
  105. Succ[impl] = new HashSet<string>();
  106. impl2functionsAsserted[impl].Iter(f =>
  107. function2implAssumed[f].Iter(succ =>
  108. {
  109. Succ[impl].Add(succ);
  110. Pred[succ].Add(impl);
  111. }));
  112. }
  113. var sccs = new StronglyConnectedComponents<string>(name2Impl.Keys,
  114. new Adjacency<string>(n => Pred[n]),
  115. new Adjacency<string>(n => Succ[n]));
  116. sccs.Compute();
  117. // impl -> priority
  118. var impl2Priority = new Dictionary<string, int>();
  119. int p = 0;
  120. foreach (var scc in sccs)
  121. {
  122. foreach (var impl in scc)
  123. {
  124. impl2Priority.Add(impl, p);
  125. p++;
  126. }
  127. }
  128. var worklist = new SortedSet<Tuple<int, string>>();
  129. name2Impl.Keys.Iter(k => worklist.Add(Tuple.Create(impl2Priority[k], k)));
  130. while (worklist.Any())
  131. {
  132. var impl = worklist.First().Item2;
  133. worklist.Remove(worklist.First());
  134. var gen = prover.VCExprGen;
  135. var terms = new List<Expr>();
  136. foreach (var tup in impl2FuncCalls[impl])
  137. {
  138. var controlVar = tup.Item2;
  139. var exprVars = tup.Item3;
  140. var varList = new List<Expr>();
  141. exprVars.Args.OfType<Expr>().Iter(v => varList.Add(v));
  142. var args = new List<Expr>();
  143. controlVar.InParams.Iter(v => args.Add(Expr.Ident(v)));
  144. Expr term = Expr.Eq(new NAryExpr(Token.NoToken, new FunctionCall(controlVar), args),
  145. function2Value[tup.Item1].Gamma(varList));
  146. if (controlVar.InParams.Count != 0)
  147. {
  148. term = new ForallExpr(Token.NoToken, new List<Variable>(controlVar.InParams.ToArray()),
  149. new Trigger(Token.NoToken, true, new List<Expr> { new NAryExpr(Token.NoToken, new FunctionCall(controlVar), args) }),
  150. term);
  151. }
  152. terms.Add(term);
  153. }
  154. var env = Expr.BinaryTreeAnd(terms);
  155. env.Typecheck(new TypecheckingContext((IErrorSink)null));
  156. var envVC = prover.Context.BoogieExprTranslator.Translate(env);
  157. var vc = gen.Implies(envVC, impl2VC[impl]);
  158. if (CommandLineOptions.Clo.Trace)
  159. {
  160. Console.WriteLine("Verifying {0}: ", impl);
  161. //Console.WriteLine("env: {0}", envVC);
  162. var envFuncs = new HashSet<string>();
  163. impl2FuncCalls[impl].Iter(tup => envFuncs.Add(tup.Item1));
  164. envFuncs.Iter(f => PrintFunction(existentialFunctions[f]));
  165. }
  166. var handler = impl2ErrorHandler[impl].Item1;
  167. var collector = impl2ErrorHandler[impl].Item2;
  168. collector.Reset(impl);
  169. var start = DateTime.Now;
  170. prover.Push();
  171. prover.Assert(gen.Not(vc), true);
  172. prover.FlushAxiomsToTheoremProver();
  173. prover.Check();
  174. ProverInterface.Outcome proverOutcome = prover.CheckOutcomeCore(handler);
  175. //prover.BeginCheck(impl, vc, handler);
  176. //ProverInterface.Outcome proverOutcome = prover.CheckOutcomeCore(handler);
  177. var inc = (DateTime.Now - start);
  178. proverTime += inc;
  179. numProverQueries++;
  180. if (CommandLineOptions.Clo.Trace)
  181. Console.WriteLine("Time taken = " + inc.TotalSeconds.ToString());
  182. if (proverOutcome == ProverInterface.Outcome.TimeOut || proverOutcome == ProverInterface.Outcome.OutOfMemory)
  183. {
  184. // pick some function; make it true and keep going
  185. bool changed = false;
  186. foreach (var f in impl2functionsAsserted[impl])
  187. {
  188. function2Value[f] = function2Value[f].MakeTop(out changed);
  189. if (changed) break;
  190. }
  191. if(!changed)
  192. return new VCGenOutcome(proverOutcome, new List<Counterexample>());
  193. }
  194. if (CommandLineOptions.Clo.Trace)
  195. Console.WriteLine(collector.numErrors > 0 ? "SAT" : "UNSAT");
  196. if (collector.numErrors > 0)
  197. {
  198. var funcsChanged = collector.funcsChanged;
  199. if (funcsChanged.Count == 0)
  200. {
  201. overallOutcome = new VCGenOutcome(ProverInterface.Outcome.Invalid, collector.errors);
  202. break;
  203. }
  204. // propagate dependent guys back into the worklist, including self
  205. var deps = new HashSet<string>();
  206. deps.Add(impl);
  207. funcsChanged.Iter(f => deps.UnionWith(function2implAssumed[f]));
  208. deps.Iter(s => worklist.Add(Tuple.Create(impl2Priority[s], s)));
  209. }
  210. prover.Pop();
  211. }
  212. if (CommandLineOptions.Clo.Trace)
  213. {
  214. Console.WriteLine("Prover time = {0}", proverTime.TotalSeconds.ToString("F2"));
  215. Console.WriteLine("Number of prover queries = " + numProverQueries);
  216. }
  217. if (CommandLineOptions.Clo.PrintAssignment)
  218. {
  219. // Print the answer
  220. existentialFunctions.Values.Iter(PrintFunction);
  221. }
  222. return overallOutcome;
  223. }
  224. public IEnumerable<Function> GetAssignment()
  225. {
  226. var ret = new List<Function>();
  227. foreach (var func in existentialFunctions.Values)
  228. {
  229. var invars = new List<Expr>(func.InParams.OfType<Variable>().Select(v => Expr.Ident(v)));
  230. func.Body = function2Value[func.Name].Gamma(invars);
  231. ret.Add(func);
  232. }
  233. return ret;
  234. }
  235. private void PrintFunction(Function function)
  236. {
  237. var tt = new TokenTextWriter(Console.Out, /*pretty=*/ false);
  238. var invars = new List<Expr>(function.InParams.OfType<Variable>().Select(v => Expr.Ident(v)));
  239. function.Body = function2Value[function.Name].Gamma(invars);
  240. function.Emit(tt, 0);
  241. tt.Close();
  242. }
  243. public HashSet<string> HandleCounterExample(string impl, Counterexample error)
  244. {
  245. var funcsChanged = new HashSet<string>();
  246. // Find the failing assert -- need to do a join there
  247. // return the set of functions whose definition has changed
  248. var cex = ExtractState(impl, error);
  249. foreach (var tup in cex)
  250. {
  251. function2Value[tup.Item1] = function2Value[tup.Item1].Join(tup.Item2);
  252. funcsChanged.Add(tup.Item1);
  253. }
  254. return funcsChanged;
  255. }
  256. private List<Tuple<string, List<Model.Element>>> ExtractState(string impl, Counterexample error)
  257. {
  258. var lastBlock = error.Trace.Last() as Block;
  259. AssertCmd failingAssert = null;
  260. CallCounterexample callCounterexample = error as CallCounterexample;
  261. if (callCounterexample != null)
  262. {
  263. Procedure failingProcedure = callCounterexample.FailingCall.Proc;
  264. Requires failingRequires = callCounterexample.FailingRequires;
  265. failingAssert = lastBlock.Cmds.OfType<AssertRequiresCmd>().FirstOrDefault(ac => ac.Requires == failingRequires);
  266. }
  267. ReturnCounterexample returnCounterexample = error as ReturnCounterexample;
  268. if (returnCounterexample != null)
  269. {
  270. Ensures failingEnsures = returnCounterexample.FailingEnsures;
  271. failingAssert = lastBlock.Cmds.OfType<AssertEnsuresCmd>().FirstOrDefault(ac => ac.Ensures == failingEnsures);
  272. }
  273. AssertCounterexample assertCounterexample = error as AssertCounterexample;
  274. if (assertCounterexample != null)
  275. {
  276. failingAssert = lastBlock.Cmds.OfType<AssertCmd>().FirstOrDefault(ac => ac == assertCounterexample.FailingAssert);
  277. }
  278. Debug.Assert(failingAssert != null);
  279. return ExtractState(impl, failingAssert.Expr, error.Model);
  280. }
  281. private static int existentialConstCounter = 0;
  282. private List<Tuple<string, List<Model.Element>>> ExtractState(string impl, Expr expr, Model model)
  283. {
  284. var funcsUsed = FunctionCollector.Collect(expr);
  285. var ret = new List<Tuple<string, List<Model.Element>>>();
  286. foreach (var tup in funcsUsed.Where(t => t.Item2 == null))
  287. {
  288. var constant = tup.Item1;
  289. if (!constant2FuncCall.ContainsKey(constant.Name))
  290. continue;
  291. var func = constant2FuncCall[constant.Name];
  292. var funcName = (func.Fun as FunctionCall).FunctionName;
  293. var vals = new List<Model.Element>();
  294. prover.Context.BoogieExprTranslator.Translate(func.Args).Iter(ve => vals.Add(getValue(ve, model)));
  295. ret.Add(Tuple.Create(funcName, vals));
  296. }
  297. foreach (var tup in funcsUsed.Where(t => t.Item2 != null))
  298. {
  299. var constant = tup.Item1;
  300. var boundExpr = tup.Item2;
  301. if (!constant2FuncCall.ContainsKey(constant.Name))
  302. continue;
  303. // There are some bound variables (because the existential function was inside an \exists).
  304. // We must find an assignment for bound varibles
  305. // First, peice apart the existential functions
  306. var cd = new Duplicator();
  307. var tup2 = ExistentialExprModelMassage.Massage(cd.VisitExpr(boundExpr.Body));
  308. var be = tup2.Item1;
  309. Expr env = Expr.True;
  310. foreach (var ahFunc in tup2.Item2)
  311. {
  312. var tup3 = impl2FuncCalls[impl].First(t => t.Item2.Name == ahFunc.Name);
  313. var varList = new List<Expr>();
  314. tup3.Item3.Args.OfType<Expr>().Iter(v => varList.Add(v));
  315. env = Expr.And(env, function2Value[tup3.Item1].Gamma(varList));
  316. }
  317. be = Expr.And(be, Expr.Not(env));
  318. // map formals to constants
  319. var formalToConstant = new Dictionary<string, Constant>();
  320. foreach (var f in boundExpr.Dummies.OfType<Variable>())
  321. formalToConstant.Add(f.Name, new Constant(Token.NoToken, new TypedIdent(Token.NoToken, f.Name + "@subst@" + (existentialConstCounter++), f.TypedIdent.Type), false));
  322. be = Substituter.Apply(new Substitution(v => formalToConstant.ContainsKey(v.Name) ? Expr.Ident(formalToConstant[v.Name]) : Expr.Ident(v)), be);
  323. formalToConstant.Values.Iter(v => prover.Context.DeclareConstant(v, false, null));
  324. var reporter = new AbstractHoudiniErrorReporter();
  325. var ve = prover.Context.BoogieExprTranslator.Translate(be);
  326. prover.Assert(ve, true);
  327. prover.Check();
  328. var proverOutcome = prover.CheckOutcomeCore(reporter);
  329. if (proverOutcome != ProverInterface.Outcome.Invalid)
  330. continue;
  331. model = reporter.model;
  332. var func = constant2FuncCall[constant.Name];
  333. var funcName = (func.Fun as FunctionCall).FunctionName;
  334. var vals = new List<Model.Element>();
  335. foreach (var funcArg in func.Args.OfType<Expr>())
  336. {
  337. var arg = Substituter.Apply(new Substitution(v => formalToConstant.ContainsKey(v.Name) ? Expr.Ident(formalToConstant[v.Name]) : Expr.Ident(v)), funcArg);
  338. vals.Add(getValue(prover.Context.BoogieExprTranslator.Translate(arg), model));
  339. }
  340. ret.Add(Tuple.Create(funcName, vals));
  341. }
  342. return ret;
  343. }
  344. private Model.Element getValue(VCExpr arg, Model model)
  345. {
  346. if (arg is VCExprLiteral)
  347. {
  348. //return model.GetElement(arg.ToString());
  349. return model.MkElement(arg.ToString());
  350. }
  351. else if (arg is VCExprVar)
  352. {
  353. var el = model.TryGetFunc(prover.Context.Lookup(arg as VCExprVar));
  354. if (el != null)
  355. {
  356. Debug.Assert(el.Arity == 0 && el.AppCount == 1);
  357. return el.Apps.First().Result;
  358. }
  359. else
  360. {
  361. // Variable not defined; assign arbitrary value
  362. if (arg.Type.IsBool)
  363. return model.MkElement("false");
  364. else if (arg.Type.IsInt)
  365. return model.MkIntElement(0);
  366. else
  367. return null;
  368. }
  369. }
  370. else if (arg is VCExprNAry && (arg as VCExprNAry).Op is VCExprBvOp)
  371. {
  372. // support for BV constants
  373. var bvc = (arg as VCExprNAry)[0] as VCExprLiteral;
  374. if (bvc != null)
  375. {
  376. var ret = model.TryMkElement(bvc.ToString() + arg.Type.ToString());
  377. if (ret != null && (ret is Model.BitVector)) return ret;
  378. }
  379. }
  380. var val = prover.Evaluate(arg);
  381. if (val is int || val is bool || val is Microsoft.Basetypes.BigNum)
  382. {
  383. return model.MkElement(val.ToString());
  384. }
  385. else
  386. {
  387. Debug.Assert(false);
  388. }
  389. return null;
  390. }
  391. // Remove functions AbsHoudiniConstant from the expressions and substitute them with "true"
  392. class ExistentialExprModelMassage : StandardVisitor
  393. {
  394. List<Function> ahFuncs;
  395. public ExistentialExprModelMassage()
  396. {
  397. ahFuncs = new List<Function>();
  398. }
  399. public static Tuple<Expr, List<Function>> Massage(Expr expr)
  400. {
  401. var ee = new ExistentialExprModelMassage();
  402. expr = ee.VisitExpr(expr);
  403. return Tuple.Create(expr, ee.ahFuncs);
  404. }
  405. public override Expr VisitNAryExpr(NAryExpr node)
  406. {
  407. if (node.Fun is FunctionCall && (node.Fun as FunctionCall).FunctionName.StartsWith("AbsHoudiniConstant"))
  408. {
  409. ahFuncs.Add((node.Fun as FunctionCall).Func);
  410. return Expr.True;
  411. }
  412. return base.VisitNAryExpr(node);
  413. }
  414. }
  415. class FunctionCollector : ReadOnlyVisitor
  416. {
  417. public List<Tuple<Function, ExistsExpr>> functionsUsed;
  418. ExistsExpr existentialExpr;
  419. public FunctionCollector()
  420. {
  421. functionsUsed = new List<Tuple<Function, ExistsExpr>>();
  422. existentialExpr = null;
  423. }
  424. public static List<Tuple<Function, ExistsExpr>> Collect(Expr expr)
  425. {
  426. var fv = new FunctionCollector();
  427. fv.VisitExpr(expr);
  428. return fv.functionsUsed;
  429. }
  430. public override QuantifierExpr VisitQuantifierExpr(QuantifierExpr node)
  431. {
  432. var oldE = existentialExpr;
  433. if (node is ExistsExpr)
  434. existentialExpr = (node as ExistsExpr);
  435. node = base.VisitQuantifierExpr(node);
  436. existentialExpr = oldE;
  437. return node;
  438. }
  439. public override Expr VisitNAryExpr(NAryExpr node)
  440. {
  441. if (node.Fun is FunctionCall)
  442. {
  443. var collector = new VariableCollector();
  444. collector.Visit(node);
  445. if(existentialExpr != null && existentialExpr.Dummies.Intersect(collector.usedVars).Any())
  446. functionsUsed.Add(Tuple.Create((node.Fun as FunctionCall).Func, existentialExpr));
  447. else
  448. functionsUsed.Add(Tuple.Create<Function, ExistsExpr>((node.Fun as FunctionCall).Func, null));
  449. }
  450. return base.VisitNAryExpr(node);
  451. }
  452. }
  453. class AbsHoudiniCounterexampleCollector : VerifierCallback
  454. {
  455. public HashSet<string> funcsChanged;
  456. public string currImpl;
  457. public int numErrors;
  458. public List<Counterexample> errors;
  459. AbsHoudini container;
  460. public AbsHoudiniCounterexampleCollector(AbsHoudini container)
  461. {
  462. this.container = container;
  463. Reset(null);
  464. }
  465. public void Reset(string impl)
  466. {
  467. funcsChanged = new HashSet<string>();
  468. currImpl = impl;
  469. numErrors = 0;
  470. errors = new List<Counterexample>();
  471. }
  472. public override void OnCounterexample(Counterexample ce, string reason)
  473. {
  474. numErrors++;
  475. errors.Add(ce);
  476. funcsChanged.UnionWith(
  477. container.HandleCounterExample(currImpl, ce));
  478. }
  479. }
  480. private void GenVC(Implementation impl)
  481. {
  482. ModelViewInfo mvInfo;
  483. Dictionary<int, Absy> label2absy;
  484. var collector = new AbsHoudiniCounterexampleCollector(this);
  485. collector.OnProgress("HdnVCGen", 0, 0, 0.0);
  486. if (CommandLineOptions.Clo.Trace)
  487. {
  488. Console.WriteLine("Generating VC of {0}", impl.Name);
  489. }
  490. vcgen.ConvertCFG2DAG(impl);
  491. var gotoCmdOrigins = vcgen.PassifyImpl(impl, out mvInfo);
  492. // Inline functions
  493. (new InlineFunctionCalls()).VisitBlockList(impl.Blocks);
  494. ExtractQuantifiedExprs(impl);
  495. StripOutermostForall(impl);
  496. //CommandLineOptions.Clo.PrintInstrumented = true;
  497. //var tt = new TokenTextWriter(Console.Out);
  498. //impl.Emit(tt, 0);
  499. //tt.Close();
  500. // Intercept the FunctionCalls of the existential functions, and replace them with Boolean constants
  501. var existentialFunctionNames = new HashSet<string>(existentialFunctions.Keys);
  502. var fv = new ReplaceFunctionCalls(existentialFunctionNames);
  503. fv.VisitBlockList(impl.Blocks);
  504. impl2functionsAsserted.Add(impl.Name, fv.functionsAsserted);
  505. impl2functionsAssumed.Add(impl.Name, fv.functionsAssumed);
  506. fv.functionsAssumed.Iter(f => function2implAssumed[f].Add(impl.Name));
  507. fv.functionsAsserted.Iter(f => function2implAsserted[f].Add(impl.Name));
  508. impl2FuncCalls.Add(impl.Name, fv.functionsUsed);
  509. fv.functionsUsed.Iter(tup => constant2FuncCall.Add(tup.Item2.Name, tup.Item3));
  510. var gen = prover.VCExprGen;
  511. VCExpr controlFlowVariableExpr = CommandLineOptions.Clo.UseLabels ? null : gen.Integer(Microsoft.Basetypes.BigNum.ZERO);
  512. var vcexpr = vcgen.GenerateVC(impl, controlFlowVariableExpr, out label2absy, prover.Context);
  513. if (!CommandLineOptions.Clo.UseLabels)
  514. {
  515. VCExpr controlFlowFunctionAppl = gen.ControlFlowFunctionApplication(gen.Integer(Microsoft.Basetypes.BigNum.ZERO), gen.Integer(Microsoft.Basetypes.BigNum.ZERO));
  516. VCExpr eqExpr = gen.Eq(controlFlowFunctionAppl, gen.Integer(Microsoft.Basetypes.BigNum.FromInt(impl.Blocks[0].UniqueId)));
  517. vcexpr = gen.Implies(eqExpr, vcexpr);
  518. }
  519. ProverInterface.ErrorHandler handler = null;
  520. if (CommandLineOptions.Clo.vcVariety == CommandLineOptions.VCVariety.Local)
  521. handler = new VCGen.ErrorReporterLocal(gotoCmdOrigins, label2absy, impl.Blocks, vcgen.incarnationOriginMap, collector, mvInfo, prover.Context, program);
  522. else
  523. handler = new VCGen.ErrorReporter(gotoCmdOrigins, label2absy, impl.Blocks, vcgen.incarnationOriginMap, collector, mvInfo, prover.Context, program);
  524. impl2ErrorHandler.Add(impl.Name, Tuple.Create(handler, collector));
  525. //Console.WriteLine("VC of {0}: {1}", impl.Name, vcexpr);
  526. // Create a macro so that the VC can sit with the theorem prover
  527. Macro macro = new Macro(Token.NoToken, impl.Name + "Macro", new List<Variable>(), new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "", Bpl.Type.Bool), false));
  528. prover.DefineMacro(macro, vcexpr);
  529. // Store VC
  530. impl2VC.Add(impl.Name, gen.Function(macro));
  531. // HACK: push the definitions of constants involved in function calls
  532. // It is possible that some constants only appear in function calls. Thus, when
  533. // they are replaced by Boolean constants, it is possible that (get-value) will
  534. // fail if the expression involves such constants. All we need to do is make sure
  535. // these constants are declared, because otherwise, semantically we are doing
  536. // the right thing.
  537. foreach (var tup in fv.functionsUsed)
  538. {
  539. // Ignore ones with bound varibles
  540. if (tup.Item2.InParams.Count > 0) continue;
  541. var tt = prover.Context.BoogieExprTranslator.Translate(tup.Item3);
  542. tt = prover.VCExprGen.Or(VCExpressionGenerator.True, tt);
  543. prover.Assert(tt, true);
  544. }
  545. }
  546. // convert "foo(... forall e ...) to:
  547. // (p iff forall e) ==> foo(... p ...)
  548. // where p is a fresh boolean variable and foo is an existential constant
  549. private void ExtractQuantifiedExprs(Implementation impl)
  550. {
  551. var funcs = new HashSet<string>(existentialFunctions.Keys);
  552. foreach (var blk in impl.Blocks)
  553. {
  554. foreach (var acmd in blk.Cmds.OfType<AssertCmd>())
  555. {
  556. var ret = ExtractQuantifiers.Extract(acmd.Expr, funcs);
  557. acmd.Expr = ret.Item1;
  558. impl.LocVars.AddRange(ret.Item2);
  559. }
  560. }
  561. }
  562. // convert "assert e1 && forall x: e2" to
  563. // assert e1 && e2[x <- x@bound]
  564. private void StripOutermostForall(Implementation impl)
  565. {
  566. var funcs = new HashSet<string>(existentialFunctions.Keys);
  567. foreach (var blk in impl.Blocks)
  568. {
  569. foreach (var acmd in blk.Cmds.OfType<AssertCmd>())
  570. {
  571. var ret = StripQuantifiers.Run(acmd.Expr, funcs);
  572. acmd.Expr = ret.Item1;
  573. impl.LocVars.AddRange(ret.Item2);
  574. }
  575. }
  576. }
  577. private void Inline()
  578. {
  579. if (CommandLineOptions.Clo.InlineDepth < 0)
  580. return;
  581. var callGraph = BuildCallGraph();
  582. foreach (Implementation impl in callGraph.Nodes)
  583. {
  584. InlineEnsuresVisitor inlineEnsuresVisitor = new InlineEnsuresVisitor();
  585. inlineEnsuresVisitor.Visit(impl);
  586. }
  587. foreach (Implementation impl in callGraph.Nodes)
  588. {
  589. impl.OriginalBlocks = impl.Blocks;
  590. impl.OriginalLocVars = impl.LocVars;
  591. }
  592. foreach (Implementation impl in callGraph.Nodes)
  593. {
  594. CommandLineOptions.Inlining savedOption = CommandLineOptions.Clo.ProcedureInlining;
  595. CommandLineOptions.Clo.ProcedureInlining = CommandLineOptions.Inlining.Spec;
  596. Inliner.ProcessImplementationForHoudini(program, impl);
  597. CommandLineOptions.Clo.ProcedureInlining = savedOption;
  598. }
  599. foreach (Implementation impl in callGraph.Nodes)
  600. {
  601. impl.OriginalBlocks = null;
  602. impl.OriginalLocVars = null;
  603. }
  604. Graph<Implementation> oldCallGraph = callGraph;
  605. callGraph = new Graph<Implementation>();
  606. foreach (Implementation impl in oldCallGraph.Nodes)
  607. {
  608. callGraph.AddSource(impl);
  609. }
  610. foreach (Tuple<Implementation, Implementation> edge in oldCallGraph.Edges)
  611. {
  612. callGraph.AddEdge(edge.Item1, edge.Item2);
  613. }
  614. int count = CommandLineOptions.Clo.InlineDepth;
  615. while (count > 0)
  616. {
  617. foreach (Implementation impl in oldCallGraph.Nodes)
  618. {
  619. List<Implementation> newNodes = new List<Implementation>();
  620. foreach (Implementation succ in callGraph.Successors(impl))
  621. {
  622. newNodes.AddRange(oldCallGraph.Successors(succ));
  623. }
  624. foreach (Implementation newNode in newNodes)
  625. {
  626. callGraph.AddEdge(impl, newNode);
  627. }
  628. }
  629. count--;
  630. }
  631. }
  632. private Graph<Implementation> BuildCallGraph()
  633. {
  634. Graph<Implementation> callGraph = new Graph<Implementation>();
  635. Dictionary<Procedure, HashSet<Implementation>> procToImpls = new Dictionary<Procedure, HashSet<Implementation>>();
  636. foreach (var proc in program.Procedures)
  637. {
  638. procToImpls[proc] = new HashSet<Implementation>();
  639. }
  640. foreach (var impl in program.Implementations)
  641. {
  642. if (impl.SkipVerification) continue;
  643. callGraph.AddSource(impl);
  644. procToImpls[impl.Proc].Add(impl);
  645. }
  646. foreach (var impl in program.Implementations)
  647. {
  648. if (impl.SkipVerification) continue;
  649. foreach (Block b in impl.Blocks)
  650. {
  651. foreach (Cmd c in b.Cmds)
  652. {
  653. CallCmd cc = c as CallCmd;
  654. if (cc == null) continue;
  655. foreach (Implementation callee in procToImpls[cc.Proc])
  656. {
  657. callGraph.AddEdge(impl, callee);
  658. }
  659. }
  660. }
  661. }
  662. return callGraph;
  663. }
  664. }
  665. class InlineFunctionCalls : StandardVisitor
  666. {
  667. public Stack<string> inlinedFunctionsStack;
  668. public InlineFunctionCalls()
  669. {
  670. inlinedFunctionsStack = new Stack<string>();
  671. }
  672. public override Expr VisitNAryExpr(NAryExpr node)
  673. {
  674. var fc = node.Fun as FunctionCall;
  675. if (fc != null && fc.Func.Body != null && QKeyValue.FindBoolAttribute(fc.Func.Attributes, "inline"))
  676. {
  677. if (inlinedFunctionsStack.Contains(fc.Func.Name))
  678. {
  679. // recursion detected
  680. throw new AbsHoudiniInternalError("Recursion detected in function declarations");
  681. }
  682. // create a substitution
  683. var subst = new Dictionary<Variable, Expr>();
  684. for (int i = 0; i < node.Args.Count; i++)
  685. {
  686. subst.Add(fc.Func.InParams[i], node.Args[i]);
  687. }
  688. var e =
  689. Substituter.Apply(new Substitution(v => subst.ContainsKey(v) ? subst[v] : Expr.Ident(v)), fc.Func.Body);
  690. inlinedFunctionsStack.Push(fc.Func.Name);
  691. e = base.VisitExpr(e);
  692. inlinedFunctionsStack.Pop();
  693. return e;
  694. }
  695. return base.VisitNAryExpr(node);
  696. }
  697. }
  698. class ReplaceFunctionCalls : StandardVisitor
  699. {
  700. public List<Tuple<string, Function, NAryExpr>> functionsUsed;
  701. public List<Function> boolConstants;
  702. public HashSet<string> functionsAssumed;
  703. public HashSet<string> functionsAsserted;
  704. HashSet<string> functionsToReplace;
  705. private bool inAssume;
  706. private bool inAssert;
  707. private bool inFunction;
  708. private List<Dictionary<string, Variable>> boundVars;
  709. private static int IdCounter = 0;
  710. public ReplaceFunctionCalls(HashSet<string> functionsToReplace)
  711. {
  712. this.functionsUsed = new List<Tuple<string, Function, NAryExpr>>();
  713. this.functionsToReplace = functionsToReplace;
  714. this.functionsAsserted = new HashSet<string>();
  715. this.functionsAssumed = new HashSet<string>();
  716. this.boolConstants = new List<Function>();
  717. this.boundVars = new List<Dictionary<string, Variable>>();
  718. inAssume = false;
  719. inAssert = false;
  720. inFunction = false;
  721. }
  722. public override Cmd VisitAssertCmd(AssertCmd node)
  723. {
  724. inAssert = true;
  725. var ret = base.VisitAssertCmd(node);
  726. inAssert = false;
  727. return ret;
  728. }
  729. public override Cmd VisitAssertEnsuresCmd(AssertEnsuresCmd node)
  730. {
  731. return this.VisitAssertCmd(node);
  732. }
  733. public override Cmd VisitAssertRequiresCmd(AssertRequiresCmd node)
  734. {
  735. return this.VisitAssertCmd(node);
  736. }
  737. public override Cmd VisitAssumeCmd(AssumeCmd node)
  738. {
  739. inAssume = true;
  740. var ret = base.VisitAssumeCmd(node);
  741. inAssume = false;
  742. return ret;
  743. }
  744. public override QuantifierExpr VisitQuantifierExpr(QuantifierExpr node)
  745. {
  746. // gather the quantified variables
  747. var dummies = new Dictionary<string, Variable>();
  748. node.Dummies.Iter(v => dummies.Add(v.Name, v));
  749. boundVars.Add(dummies);
  750. node = base.VisitQuantifierExpr(node);
  751. boundVars.RemoveAt(boundVars.Count - 1);
  752. return node;
  753. }
  754. public override Expr VisitNAryExpr(NAryExpr node)
  755. {
  756. var inF = inFunction;
  757. if (node.Fun is FunctionCall && functionsToReplace.Contains((node.Fun as FunctionCall).FunctionName))
  758. {
  759. found((node.Fun as FunctionCall).FunctionName);
  760. inFunction = true;
  761. // collect all the variables used by this function
  762. var collector = new VariableCollector();
  763. collector.VisitExpr(node);
  764. // Find the outermost bound variables
  765. var bound = new List<Variable>();
  766. if(boundVars.Count > 0)
  767. bound.AddRange(collector.usedVars.Intersect(boundVars[0].Values));
  768. // create boolean function to replace this guy
  769. var constant = new Function(Token.NoToken, "AbsHoudiniConstant" + IdCounter, bound,
  770. new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "r", Microsoft.Boogie.Type.Bool), false));
  771. IdCounter++;
  772. functionsUsed.Add(Tuple.Create((node.Fun as FunctionCall).FunctionName, constant, node));
  773. boolConstants.Add(constant);
  774. var args = new List<Expr>();
  775. bound.OfType<Variable>().Select(v => Expr.Ident(v)).Iter(v => args.Add(v));
  776. return new NAryExpr(Token.NoToken, new FunctionCall(constant), args);
  777. }
  778. var ret = base.VisitNAryExpr(node);
  779. inFunction = inF;
  780. return ret;
  781. }
  782. public override Expr VisitIdentifierExpr(IdentifierExpr node)
  783. {
  784. if (inFunction)
  785. {
  786. // Inside functions we can only refer to the outermost bound variables
  787. for (int i = boundVars.Count - 1; i >= 1; i--)
  788. {
  789. if (boundVars[i].ContainsKey(node.Name))
  790. throw new AbsHoudiniInternalError("Existential functions can only refer to outermost bound variables in an expression");
  791. }
  792. }
  793. return base.VisitIdentifierExpr(node);
  794. }
  795. private void found(string func)
  796. {
  797. if (inAssume) functionsAssumed.Add(func);
  798. if (inAssert) functionsAsserted.Add(func);
  799. }
  800. }
  801. // convert "foo(... forall e ...) to:
  802. // (p iff forall e) ==> foo(... p ...)
  803. // where p is a fresh boolean variable and foo is an existential constant
  804. class ExtractQuantifiers : StandardVisitor
  805. {
  806. static int freshConstCounter = 0;
  807. HashSet<string> existentialFunctions;
  808. bool insideExistential;
  809. Dictionary<Constant, Expr> newConstants;
  810. private ExtractQuantifiers(HashSet<string> existentialFunctions)
  811. {
  812. this.existentialFunctions = existentialFunctions;
  813. insideExistential = false;
  814. newConstants = new Dictionary<Constant, Expr>();
  815. }
  816. public static Tuple<Expr, IEnumerable<Constant>> Extract(Expr expr, HashSet<string> existentialFunctions)
  817. {
  818. var eq = new ExtractQuantifiers(existentialFunctions);
  819. expr = eq.VisitExpr(expr);
  820. Expr ret = Expr.True;
  821. foreach (var tup in eq.newConstants)
  822. {
  823. ret = Expr.And(ret, Expr.Eq(Expr.Ident(tup.Key), tup.Value));
  824. }
  825. ret = Expr.Imp(ret, expr);
  826. return Tuple.Create(ret, eq.newConstants.Keys.AsEnumerable());
  827. }
  828. public override Expr VisitNAryExpr(NAryExpr node)
  829. {
  830. var oldIE = insideExistential;
  831. if (node.Fun is FunctionCall && existentialFunctions.Contains((node.Fun as FunctionCall).FunctionName))
  832. insideExistential = true;
  833. var ret = base.VisitNAryExpr(node);
  834. insideExistential = oldIE;
  835. return ret;
  836. }
  837. public override Expr VisitExpr(Expr node)
  838. {
  839. if (node is QuantifierExpr)
  840. {
  841. return MyVisitQuantifierExpr(node as QuantifierExpr);
  842. }
  843. return base.VisitExpr(node);
  844. }
  845. public Expr MyVisitQuantifierExpr(QuantifierExpr node)
  846. {
  847. node = base.VisitQuantifierExpr(node);
  848. if (insideExistential)
  849. {
  850. var constant = new Constant(Token.NoToken, new TypedIdent(Token.NoToken,
  851. "quant@const" + freshConstCounter, Microsoft.Boogie.Type.Bool), false);
  852. freshConstCounter++;
  853. newConstants.Add(constant, node);
  854. return Expr.Ident(constant);
  855. }
  856. return node;
  857. }
  858. }
  859. // convert "assert e1 && forall x: e2" to
  860. // assert e1 && e2[x <- x@bound]
  861. // only if e2 has an existential function
  862. class StripQuantifiers : StandardVisitor
  863. {
  864. static int boundVarCounter = 0;
  865. // 0 -> None, 1 -> Forall, 2 -> Exists, 3 -> Nested
  866. int insideQuantifier;
  867. bool searchExistentialFunction;
  868. bool foundExistentialFunction;
  869. HashSet<string> existentialFunctions;
  870. Dictionary<string, LocalVariable> subst;
  871. List<LocalVariable> LocalsToAdd;
  872. private StripQuantifiers(HashSet<string> existentialFunctions)
  873. {
  874. this.existentialFunctions = existentialFunctions;
  875. insideQuantifier = 0;
  876. searchExistentialFunction = false;
  877. foundExistentialFunction = false;
  878. LocalsToAdd = new List<LocalVariable>();
  879. subst = null;
  880. }
  881. public static Tuple<Expr,List<LocalVariable>> Run(Expr expr, HashSet<string> existentialFunctions)
  882. {
  883. // check for type errors first
  884. var sq = new StripQuantifiers(existentialFunctions);
  885. var ret = sq.VisitExpr(expr);
  886. return Tuple.Create(ret, sq.LocalsToAdd);
  887. }
  888. public override Expr VisitExpr(Expr node)
  889. {
  890. if (node is QuantifierExpr)
  891. {
  892. return MyVisitQuantifierExpr(node as QuantifierExpr);
  893. }
  894. return base.VisitExpr(node);
  895. }
  896. private Expr MyVisitQuantifierExpr(QuantifierExpr node)
  897. {
  898. var oldIQ = insideQuantifier;
  899. Expr ret = node;
  900. // update "insideQuantifier"
  901. if (insideQuantifier == 0)
  902. {
  903. if (node is ForallExpr) insideQuantifier = 1;
  904. else insideQuantifier = 2;
  905. }
  906. else if (insideQuantifier > 0)
  907. {
  908. insideQuantifier = 3;
  909. }
  910. // Going inside Forall?
  911. if (insideQuantifier == 1)
  912. {
  913. // see if there is any existential function inside
  914. searchExistentialFunction = true;
  915. foundExistentialFunction = false;
  916. base.VisitQuantifierExpr(node);
  917. if (foundExistentialFunction)
  918. {
  919. // create substitution to apply
  920. subst = new Dictionary<string, LocalVariable>();
  921. foreach (var bv in node.Dummies.OfType<Variable>())
  922. {
  923. var lv = new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken,
  924. bv + "@bound" + boundVarCounter, bv.TypedIdent.Type));
  925. boundVarCounter++;
  926. subst.Add(bv.Name, lv);
  927. LocalsToAdd.Add(lv);
  928. }
  929. // apply the subst
  930. var body = base.VisitExpr(node.Body);
  931. ret = body;
  932. subst = null;
  933. }
  934. else
  935. {
  936. ret = base.VisitQuantifierExpr(node);
  937. }
  938. searchExistentialFunction = false;
  939. foundExistentialFunction = false;
  940. }
  941. else
  942. {
  943. ret = base.VisitQuantifierExpr(node);
  944. }
  945. insideQuantifier = oldIQ;
  946. return ret;
  947. }
  948. public override Expr VisitNAryExpr(NAryExpr node)
  949. {
  950. if (node.Fun is FunctionCall && existentialFunctions.Contains((node.Fun as FunctionCall).FunctionName))
  951. {
  952. if (insideQuantifier == 3)
  953. throw new AbsHoudiniInternalError("Existential function found inside exists, or nested foralls");
  954. if (searchExistentialFunction)
  955. foundExistentialFunction = true;
  956. }
  957. return base.VisitNAryExpr(node);
  958. }
  959. public override Expr VisitIdentifierExpr(IdentifierExpr node)
  960. {
  961. if (subst != null && subst.ContainsKey(node.Name))
  962. return Expr.Ident(subst[node.Name]);
  963. return base.VisitIdentifierExpr(node);
  964. }
  965. }
  966. public class Intervals : IAbstractDomain
  967. {
  968. // [lower, upper]
  969. int upper;
  970. int lower;
  971. // or: \bot
  972. bool isBottom;
  973. // number of times join has been performed
  974. int nJoin;
  975. // number of times before we widen
  976. readonly static int maxJoin = 5;
  977. public Intervals()
  978. {
  979. this.upper = 0;
  980. this.lower = 0;
  981. this.nJoin = 0;
  982. this.isBottom = true;
  983. }
  984. private Intervals(int lower, int upper, int nJoin)
  985. {
  986. this.upper = upper;
  987. this.lower = lower;
  988. this.nJoin = nJoin;
  989. }
  990. public IAbstractDomain Bottom()
  991. {
  992. return new Intervals();
  993. }
  994. public IAbstractDomain MakeTop(out bool changed)
  995. {
  996. if (lower == Int32.MinValue && upper == Int32.MaxValue)
  997. {
  998. changed = false;
  999. return this;
  1000. }
  1001. changed = true;
  1002. return new Intervals(Int32.MinValue, Int32.MaxValue, 0);
  1003. }
  1004. public IAbstractDomain Join(List<Model.Element> states)
  1005. {
  1006. Debug.Assert(states.Count == 1);
  1007. var state = states[0] as Model.Integer;
  1008. if (state == null)
  1009. throw new AbsHoudiniInternalError("Incorrect type, expected int");
  1010. var intval = state.AsInt();
  1011. if (isBottom)
  1012. {
  1013. return new Intervals(intval, intval, 1);
  1014. }
  1015. if(intval >= lower && intval <= upper)
  1016. return this;
  1017. if (nJoin > maxJoin)
  1018. {
  1019. // widen
  1020. if (intval > upper)
  1021. return new Intervals(lower, Int32.MaxValue, 1);
  1022. if(intval < lower)
  1023. return new Intervals(Int32.MinValue, upper, 1);
  1024. Debug.Assert(false);
  1025. }
  1026. if (intval > upper)
  1027. return new Intervals(lower, intval, nJoin + 1);
  1028. if (intval < lower)
  1029. return new Intervals(intval, upper, nJoin + 1);
  1030. Debug.Assert(false);
  1031. return null;
  1032. }
  1033. public Expr Gamma(List<Expr> vars)
  1034. {
  1035. Debug.Assert(vars.Count == 1);
  1036. var v = vars[0];
  1037. if (isBottom) return Expr.False;
  1038. Expr ret = Expr.True;
  1039. if (lower != Int32.MinValue)
  1040. ret = Expr.And(ret, Expr.Ge(v, Expr.Literal(lower)));
  1041. if (upper != Int32.MaxValue)
  1042. ret = Expr.And(ret, Expr.Le(v, Expr.Literal(upper)));
  1043. return ret;
  1044. }
  1045. public bool TypeCheck(List<Type> argTypes, out string msg)
  1046. {
  1047. msg = "";
  1048. if (argTypes.Count != 1)
  1049. {
  1050. msg = "Illegal number of arguments";
  1051. return false;
  1052. }
  1053. if (!argTypes[0].IsInt)
  1054. {
  1055. msg = "Illegal type, expecting int";
  1056. return false;
  1057. }
  1058. return true;
  1059. }
  1060. }
  1061. public class PredicateAbsElem : IAbstractDomain
  1062. {
  1063. public static class ExprExt
  1064. {
  1065. public static Expr AndSimp(Expr e1, Expr e2)
  1066. {
  1067. if (e1 == Expr.True) return e2;
  1068. if (e2 == Expr.True) return e1;
  1069. if (e1 == Expr.False || e2 == Expr.False) return Expr.False;
  1070. return Expr.And(e1, e2);
  1071. }
  1072. public static Expr OrSimp(Expr e1, Expr e2)
  1073. {
  1074. if (e1 == Expr.False) return e2;
  1075. if (e2 == Expr.False) return e1;
  1076. if (e1 == Expr.True || e2 == Expr.True) return Expr.True;
  1077. return Expr.Or(e1, e2);
  1078. }
  1079. }
  1080. class Disjunct
  1081. {
  1082. public static int DisjunctBound = 3;
  1083. HashSet<int> pos;
  1084. HashSet<int> neg;
  1085. bool isTrue;
  1086. public Disjunct()
  1087. {
  1088. isTrue = true;
  1089. pos = new HashSet<int>();
  1090. neg = new HashSet<int>();
  1091. }
  1092. public Disjunct(IEnumerable<int> pos, IEnumerable<int> neg)
  1093. {
  1094. this.isTrue = false;
  1095. this.pos = new HashSet<int>(pos);
  1096. this.neg = new HashSet<int>(neg);
  1097. if (this.pos.Overlaps(this.neg))
  1098. {
  1099. this.isTrue = true;
  1100. this.pos = new HashSet<int>();
  1101. this.neg = new HashSet<int>();
  1102. }
  1103. if (this.pos.Count + this.neg.Count > DisjunctBound)
  1104. {
  1105. // Set to true
  1106. this.isTrue = true;
  1107. this.pos = new HashSet<int>();
  1108. this.neg = new HashSet<int>();
  1109. }
  1110. }
  1111. public Disjunct OR(Disjunct that)
  1112. {
  1113. if (isTrue)
  1114. return this;
  1115. if (that.isTrue)
  1116. return that;
  1117. return new Disjunct(this.pos.Concat(that.pos), this.neg.Concat(that.neg));
  1118. }
  1119. public bool Implies(Disjunct that)
  1120. {
  1121. if (isTrue) return that.isTrue;
  1122. if (that.isTrue) return true;
  1123. return pos.IsSubsetOf(that.pos) && neg.IsSubsetOf(that.neg);
  1124. }
  1125. public Expr Gamma(List<Expr> vars)
  1126. {
  1127. if (isTrue) return Expr.True;
  1128. Expr ret = Expr.False;
  1129. pos.Iter(i => ret = ExprExt.OrSimp(ret, vars[i]));
  1130. neg.Iter(i => ret = ExprExt.OrSimp(ret, Expr.Not(vars[i])));
  1131. return ret;
  1132. }
  1133. }
  1134. // Conjunction of Disjuncts
  1135. List<Disjunct> conjuncts;
  1136. bool isFalse;
  1137. public PredicateAbsElem()
  1138. {
  1139. this.conjuncts = new List<Disjunct>();
  1140. this.isFalse = true;
  1141. }
  1142. public IAbstractDomain Bottom()
  1143. {
  1144. return new PredicateAbsElem();
  1145. }
  1146. public IAbstractDomain MakeTop(out bool changed)
  1147. {
  1148. if (conjuncts.Count == 0)
  1149. {
  1150. changed = false;
  1151. return this;
  1152. }
  1153. changed = true;
  1154. var ret = new PredicateAbsElem();
  1155. ret.isFalse = false;
  1156. return ret;
  1157. }
  1158. public IAbstractDomain Join(List<Model.Element> state)
  1159. {
  1160. if (state.Any(me => !(me is Model.Boolean)))
  1161. throw new AbsHoudiniInternalError("Predicate Abstraction requires that each argument be of type bool");
  1162. // quick return if this == true
  1163. if (!this.isFalse && conjuncts.Count == 0)
  1164. return this;
  1165. var ret = new PredicateAbsElem();
  1166. ret.isFalse = false;
  1167. for (int i = 0; i < state.Count; i++)
  1168. {
  1169. var b = (state[i] as Model.Boolean).Value;
  1170. Disjunct d = null;
  1171. if (b) d = new Disjunct(new int[] { i }, new int[] { });
  1172. else d = new Disjunct(new int[] { }, new int[] { i });
  1173. if (isFalse)
  1174. ret.AddDisjunct(d);
  1175. else
  1176. {
  1177. conjuncts.Iter(c => ret.AddDisjunct(c.OR(d)));
  1178. }
  1179. }
  1180. return ret;
  1181. }
  1182. public Expr Gamma(List<Expr> vars)
  1183. {
  1184. if (isFalse) return Expr.False;
  1185. Expr ret = Expr.True;
  1186. foreach (var c in conjuncts)
  1187. {
  1188. ret = ExprExt.AndSimp(ret, c.Gamma(vars));
  1189. }
  1190. return ret;
  1191. }
  1192. public bool TypeCheck(List<Type> argTypes, out string msg)
  1193. {
  1194. msg = "";
  1195. if (argTypes.Any(t => !t.IsBool))
  1196. {
  1197. msg = "Illegal type, expecting bool";
  1198. return false;
  1199. }
  1200. return true;
  1201. }
  1202. private void AddDisjunct(Disjunct d)
  1203. {
  1204. if (conjuncts.Any(c => c.Implies(d)))
  1205. return;
  1206. conjuncts.RemoveAll(c => d.Implies(c));
  1207. conjuncts.Add(d);
  1208. }
  1209. }
  1210. // [false -- (x == true) -- true]
  1211. public class HoudiniConst : IAbstractDomain
  1212. {
  1213. bool isBottom;
  1214. bool isTop;
  1215. private HoudiniConst(bool isTop, bool isBottom)
  1216. {
  1217. this.isBottom = isBottom;
  1218. this.isTop = isTop;
  1219. Debug.Assert(!(isTop && isBottom));
  1220. }
  1221. public static HoudiniConst GetExtObj()
  1222. {
  1223. return new HoudiniConst(false, false);
  1224. }
  1225. public static HoudiniConst GetTop()
  1226. {
  1227. return new HoudiniConst(true, false);
  1228. }
  1229. public static HoudiniConst GetBottom()
  1230. {
  1231. return new HoudiniConst(false, true);
  1232. }
  1233. public IAbstractDomain Bottom()
  1234. {
  1235. return GetBottom();
  1236. }
  1237. public IAbstractDomain MakeTop(out bool changed)
  1238. {
  1239. changed = false;
  1240. if (isTop) return this;
  1241. changed = true;
  1242. return GetTop();
  1243. }
  1244. public IAbstractDomain Join(List<Model.Element> states)
  1245. {
  1246. Debug.Assert(states.Count == 1);
  1247. var state = states[0];
  1248. if (isTop) return this;
  1249. if (state is Model.Boolean)
  1250. {
  1251. if ((state as Model.Boolean).Value)
  1252. return GetExtObj();
  1253. }
  1254. return GetTop();
  1255. }
  1256. public Expr Gamma(List<Expr> vars)
  1257. {
  1258. Debug.Assert(vars.Count == 1);
  1259. var v = vars[0];
  1260. if (isBottom) return Expr.False;
  1261. if (isTop) return Expr.True;
  1262. return v;
  1263. }
  1264. public bool TypeCheck(List<Type> argTypes, out string msg)
  1265. {
  1266. msg = "";
  1267. if (argTypes.Count != 1)
  1268. {
  1269. msg = "Illegal number of arguments, expecting 1";
  1270. return false;
  1271. }
  1272. if (!argTypes[0].IsBool)
  1273. {
  1274. msg = "Illegal type, expecting bool";
  1275. return false;
  1276. }
  1277. return true;
  1278. }
  1279. }
  1280. // foo(x) = x < 2^j for some j <= 16
  1281. public class PowDomain : IAbstractDomain
  1282. {
  1283. enum Val { FALSE, NEITHER, TRUE };
  1284. Val tlevel;
  1285. bool isBottom { get { return tlevel == Val.FALSE; } }
  1286. bool isTop { get { return tlevel == Val.TRUE; } }
  1287. readonly int Max = 16;
  1288. int upper; // <= Max
  1289. private PowDomain(Val tlevel) :
  1290. this(tlevel, 0) { }
  1291. private PowDomain(Val tlevel, int upper)
  1292. {
  1293. this.tlevel = tlevel;
  1294. this.upper = upper;
  1295. }
  1296. public static IAbstractDomain GetBottom()
  1297. {
  1298. return new PowDomain(Val.FALSE) as IAbstractDomain;
  1299. }
  1300. public IAbstractDomain MakeTop(out bool changed)
  1301. {
  1302. if (isTop)
  1303. {
  1304. changed = false;
  1305. return this;
  1306. }
  1307. changed = true;
  1308. return new PowDomain(Val.TRUE);
  1309. }
  1310. IAbstractDomain IAbstractDomain.Bottom()
  1311. {
  1312. return GetBottom();
  1313. }
  1314. IAbstractDomain IAbstractDomain.Join(List<Model.Element> state)
  1315. {
  1316. if (isTop) return this;
  1317. int v = 0;
  1318. if (state[0] is Model.BitVector)
  1319. v = (state[0] as Model.BitVector).AsInt();
  1320. else if (state[0] is Model.Integer)
  1321. v = (state[0] as Model.Integer).AsInt();
  1322. else Debug.Assert(false);
  1323. var nupper = upper;
  1324. while ((1 << nupper) < v) nupper++;
  1325. var ntlevel = Val.NEITHER;
  1326. if (nupper > Max) ntlevel = Val.TRUE;
  1327. return new PowDomain(ntlevel, nupper);
  1328. }
  1329. Expr IAbstractDomain.Gamma(List<Expr> vars)
  1330. {
  1331. if (isBottom) return Expr.False;
  1332. if (isTop) return Expr.True;
  1333. var v = vars[0];
  1334. if (v.Type.IsBv)
  1335. {
  1336. var bits = v.Type.BvBits;
  1337. if (!AbstractDomainFactory.bvslt.ContainsKey(bits))
  1338. throw new AbsHoudiniInternalError("No builtin function found for bv" + bits.ToString());
  1339. var bvslt = AbstractDomainFactory.bvslt[bits];
  1340. return new NAryExpr(Token.NoToken, new FunctionCall(bvslt), new List<Expr> { v,
  1341. new LiteralExpr(Token.NoToken, Basetypes.BigNum.FromInt(1 << (upper+1)), 32) });
  1342. }
  1343. else
  1344. {
  1345. return Expr.Lt(v, Expr.Literal(1 << (upper+1)));
  1346. }
  1347. }
  1348. bool IAbstractDomain.TypeCheck(List<Type> argTypes, out string msg)
  1349. {
  1350. msg = "";
  1351. if (argTypes.Count != 1)
  1352. {
  1353. msg = "Illegal number of arguments, expecting 1";
  1354. return false;
  1355. }
  1356. if (argTypes.Any(tt => !tt.IsInt && !tt.IsBv))
  1357. {
  1358. msg = "Illegal type, expecting int or bv";
  1359. return false;
  1360. }
  1361. return true;
  1362. }
  1363. }
  1364. // foo(x_i) = all equalities that hold
  1365. public class EqualitiesDomain : IAbstractDomain
  1366. {
  1367. bool isBottom;
  1368. List<HashSet<int>> equalities;
  1369. public EqualitiesDomain(bool isBottom, List<HashSet<int>> eq)
  1370. {
  1371. this.isBottom = isBottom;
  1372. this.equalities = eq;
  1373. }
  1374. public static IAbstractDomain GetBottom()
  1375. {
  1376. return new EqualitiesDomain(true, new List<HashSet<int>>());
  1377. }
  1378. IAbstractDomain IAbstractDomain.Bottom()
  1379. {
  1380. return GetBottom();
  1381. }
  1382. public IAbstractDomain MakeTop(out bool changed)
  1383. {
  1384. if (equalities.Count == 0)
  1385. {
  1386. changed = false;
  1387. return this;
  1388. }
  1389. changed = true;
  1390. return new EqualitiesDomain(false, new List<HashSet<int>>());
  1391. }
  1392. IAbstractDomain IAbstractDomain.Join(List<Model.Element> state)
  1393. {
  1394. // find the guys that are equal
  1395. var eq = new List<HashSet<int>>();
  1396. for (int i = 0; i < state.Count; i++)
  1397. {
  1398. var added = false;
  1399. foreach (var s in eq)
  1400. {
  1401. var sv = s.First();
  1402. if (state[i].ToString() == state[sv].ToString())
  1403. {
  1404. s.Add(i);
  1405. added = true;
  1406. break;
  1407. }
  1408. }
  1409. if (!added) eq.Add(new HashSet<int>(new int[] { i }));
  1410. }
  1411. if (isBottom)
  1412. {
  1413. return new EqualitiesDomain(false, eq);
  1414. }
  1415. // intersect two partitions equalities and eq
  1416. var m1 = GetMap(equalities, state.Count);
  1417. var m2 = GetMap(eq, state.Count);
  1418. for (int i = 0; i < state.Count; i++)
  1419. m2[i] = new HashSet<int>(m2[i].Intersect(m1[i]));
  1420. // map from representative to set
  1421. var repToSet = new Dictionary<int, HashSet<int>>();
  1422. for (int i = 0; i < state.Count; i++)
  1423. {
  1424. var rep = m2[i].Min();
  1425. if (!repToSet.ContainsKey(rep))
  1426. repToSet[rep] = m2[i];
  1427. }
  1428. var ret = new List<HashSet<int>>();
  1429. repToSet.Values.Iter(s => ret.Add(s));
  1430. return new EqualitiesDomain(false, ret);
  1431. }
  1432. Expr IAbstractDomain.Gamma(List<Expr> vars)
  1433. {
  1434. if (isBottom) return Expr.False;
  1435. Expr ret = Expr.True;
  1436. foreach (var eq in equalities.Select(hs => hs.ToList()))
  1437. {
  1438. if (eq.Count == 1) continue;
  1439. var prev = eq[0];
  1440. for (int i = 1; i < eq.Count; i++)
  1441. {
  1442. ret = Expr.And(ret, Expr.Eq(vars[prev], vars[eq[i]]));
  1443. prev = eq[i];
  1444. }
  1445. }
  1446. return ret;
  1447. }
  1448. bool IAbstractDomain.TypeCheck(List<Type> argTypes, out string msg)
  1449. {
  1450. msg = "";
  1451. if (argTypes.Count == 0) return true;
  1452. var ot = argTypes[0];
  1453. if (argTypes.Any(tt => !tt.Equals(ot)))
  1454. {
  1455. msg = string.Format("Illegal type, expecting type {0}, got {1}", ot, argTypes.First(tt => !tt.Equals(ot)));
  1456. return false;
  1457. }
  1458. return true;
  1459. }
  1460. private HashSet<int>[] GetMap(List<HashSet<int>> eq, int n)
  1461. {
  1462. var ret = new HashSet<int>[n];
  1463. foreach (var s in eq)
  1464. {
  1465. foreach (var i in s)
  1466. ret[i] = s;
  1467. }
  1468. return ret;
  1469. }
  1470. }
  1471. // foo(a,b) \in {false, \not a, a ==> b, true}
  1472. public class ImplicationDomain : IAbstractDomain
  1473. {
  1474. enum Val {FALSE, NOT_A, A_IMP_B, TRUE};
  1475. Val val;
  1476. private ImplicationDomain(Val val)
  1477. {
  1478. this.val = val;
  1479. }
  1480. public static ImplicationDomain GetBottom()
  1481. {
  1482. return new ImplicationDomain(Val.FALSE);
  1483. }
  1484. public IAbstractDomain Bottom()
  1485. {
  1486. return GetBottom();
  1487. }
  1488. public IAbstractDomain MakeTop(out bool changed)
  1489. {
  1490. if(val == Val.TRUE) {
  1491. changed = false;
  1492. return this;
  1493. }
  1494. changed = true;
  1495. return new ImplicationDomain(Val.TRUE);
  1496. }
  1497. public IAbstractDomain Join(List<Model.Element> states)
  1498. {
  1499. Debug.Assert(states.Count == 2);
  1500. var v1 = (states[0] as Model.Boolean).Value;
  1501. var v2 = (states[1] as Model.Boolean).Value;
  1502. if (val == Val.TRUE) return this;
  1503. var that = Val.TRUE;
  1504. if (!v1) that = Val.NOT_A;
  1505. else if (!v1 || v2) that = Val.A_IMP_B;
  1506. if (that == Val.TRUE || val == Val.FALSE)
  1507. return new ImplicationDomain(that);
  1508. // Now, neither this or that is FALSE or TRUE
  1509. if (val == that)
  1510. return this;
  1511. Debug.Assert(val == Val.A_IMP_B || that == Val.A_IMP_B);
  1512. return new ImplicationDomain(Val.A_IMP_B);
  1513. }
  1514. public Expr Gamma(List<Expr> vars)
  1515. {
  1516. Debug.Assert(vars.Count == 2);
  1517. var v1 = vars[0];
  1518. var v2 = vars[1];
  1519. if (val == Val.FALSE) return Expr.False;
  1520. if (val == Val.TRUE) return Expr.True;
  1521. if (val == Val.NOT_A) return Expr.Not(v1);
  1522. return Expr.Imp(v1, v2);
  1523. }
  1524. public bool TypeCheck(List<Type> argTypes, out string msg)
  1525. {
  1526. msg = "";
  1527. if (argTypes.Count != 2)
  1528. {
  1529. msg = "Illegal number of arguments, expecting 2";
  1530. return false;
  1531. }
  1532. if (argTypes.Any(tt => !tt.IsBool))
  1533. {
  1534. msg = "Illegal type, expecting bool";
  1535. return false;
  1536. }
  1537. return true;
  1538. }
  1539. }
  1540. public class ConstantProp : IAbstractDomain
  1541. {
  1542. object val;
  1543. bool isBottom;
  1544. bool isTop;
  1545. private ConstantProp(object val, bool isTop, bool isBottom)
  1546. {
  1547. this.val = val;
  1548. this.isBottom = isBottom;
  1549. this.isTop = isTop;
  1550. Debug.Assert(!(isTop && isBottom));
  1551. Debug.Assert(val == null || (val is int) || (val is bool));
  1552. }
  1553. public static ConstantProp GetExtObj(object val)
  1554. {
  1555. Debug.Assert(val != null);
  1556. return new ConstantProp(val, false, false);
  1557. }
  1558. public static ConstantProp GetTop()
  1559. {
  1560. return new ConstantProp(null, true, false);
  1561. }
  1562. public static ConstantProp GetBottom()
  1563. {
  1564. return new ConstantProp(null, false, true);
  1565. }
  1566. public IAbstractDomain MakeTop(out bool changed) {
  1567. if (isTop)
  1568. {
  1569. changed = false;
  1570. return this;
  1571. }
  1572. changed = true;
  1573. return GetTop();
  1574. }
  1575. private ConstantProp Join(ConstantProp that)
  1576. {
  1577. if (isBottom) return that;
  1578. if (isTop) return this;
  1579. if (that.isBottom) return this;
  1580. if (that.isTop) return that;
  1581. if ((val is int) && !(that.val is int))
  1582. throw new AbsHoudiniInternalError("Type mismatch in ExtObj");
  1583. if ((val is bool) && !(that.val is bool))
  1584. throw new AbsHoudiniInternalError("Type mismatch in ExtObj");
  1585. if (val is int)
  1586. {
  1587. var v1 = (int)val;
  1588. var v2 = (int)that.val;
  1589. if (v1 != v2) return GetTop();
  1590. return this;
  1591. }
  1592. else if (val is bool)
  1593. {
  1594. var v1 = (bool)val;
  1595. var v2 = (bool)that.val;
  1596. if (v1 != v2) return GetTop();
  1597. return this;
  1598. }
  1599. throw new AbsHoudiniInternalError("Illegal val type in ExtObj");
  1600. }
  1601. public IAbstractDomain Bottom()
  1602. {
  1603. return GetBottom();
  1604. }
  1605. public IAbstractDomain Join(List<Model.Element> states)
  1606. {
  1607. Debug.Assert(states.Count == 1);
  1608. var state = states[0];
  1609. ConstantProp that = null;
  1610. if (state is Model.Integer)
  1611. {
  1612. that = GetExtObj((state as Model.Integer).AsInt());
  1613. }
  1614. else if (state is Model.Boolean)
  1615. {
  1616. that = GetExtObj((state as Model.Boolean).Value);
  1617. }
  1618. else
  1619. {
  1620. throw new AbsHoudiniInternalError("Illegal type " + state.GetType().ToString());
  1621. }
  1622. return Join(that);
  1623. }
  1624. public Expr Gamma(List<Expr> vars)
  1625. {
  1626. Debug.Assert(vars.Count == 1);
  1627. var v = vars[0];
  1628. if (isBottom) return Expr.False;
  1629. if (isTop) return Expr.True;
  1630. if (val is int)
  1631. return Expr.Eq(v, Expr.Literal((int)val));
  1632. if (val is bool && (bool)val)
  1633. return v;
  1634. if (val is bool && !(bool)val)
  1635. return Expr.Not(v);
  1636. return null;
  1637. }
  1638. public bool TypeCheck(List<Type> argTypes, out string msg)
  1639. {
  1640. msg = "";
  1641. if (argTypes.Count != 1)
  1642. {
  1643. msg = "Illegal number of arguments, expecting 1";
  1644. return false;
  1645. }
  1646. if (!argTypes[0].IsInt && ! argTypes[0].IsBool)
  1647. {
  1648. msg = "Illegal type, expecting int or bool";
  1649. return false;
  1650. }
  1651. return true;
  1652. }
  1653. }
  1654. public class IndependentAttribute<T> : IAbstractDomain where T : class, IAbstractDomain
  1655. {
  1656. bool isBottom;
  1657. int numVars;
  1658. List<T> varVal;
  1659. T underlyingInstance;
  1660. public IndependentAttribute()
  1661. {
  1662. isBottom = true;
  1663. numVars = 0;
  1664. varVal = new List<T>();
  1665. underlyingInstance = null;
  1666. }
  1667. public IAbstractDomain Bottom()
  1668. {
  1669. return new IndependentAttribute<T>();
  1670. }
  1671. public IAbstractDomain MakeTop(out bool changed)
  1672. {
  1673. var mt = new Func<IAbstractDomain>(() =>
  1674. {
  1675. var ret = new IndependentAttribute<T>();
  1676. ret.isBottom = true;
  1677. ret.numVars = numVars;
  1678. ret.underlyingInstance = underlyingInstance;
  1679. ret.varVal = new List<T>();
  1680. bool tmp;
  1681. for (int i = 0; i < varVal.Count; i++)
  1682. ret.varVal.Add(varVal[i].MakeTop(out tmp) as T);
  1683. return ret;
  1684. });
  1685. if (!isBottom)
  1686. {
  1687. foreach (var t in varVal)
  1688. {
  1689. var top = t.MakeTop(out changed);
  1690. if (changed)
  1691. {
  1692. return mt();
  1693. }
  1694. }
  1695. }
  1696. else
  1697. {
  1698. changed = true;
  1699. return mt();
  1700. }
  1701. changed = false;
  1702. return this;
  1703. }
  1704. public IAbstractDomain Join(List<Model.Element> state)
  1705. {
  1706. SetUnderlyingInstance();
  1707. if (!isBottom && numVars != state.Count)
  1708. {
  1709. throw new AbsHoudiniInternalError(
  1710. string.Format("Got illegal number of arguments ({0}), expected {1}", state.Count, numVars));
  1711. }
  1712. var ret = new IndependentAttribute<T>();
  1713. ret.isBottom = false;
  1714. ret.numVars = state.Count;
  1715. for(int i = 0; i < state.Count; i++)
  1716. {
  1717. var sl = new List<Model.Element>();
  1718. sl.Add(state[i]);
  1719. T prev = isBottom ? underlyingInstance.Bottom() as T : varVal[i];
  1720. ret.varVal.Add(prev.Join(sl) as T);
  1721. }
  1722. return ret;
  1723. }
  1724. public Expr Gamma(List<Expr> vars)
  1725. {
  1726. if (isBottom) return Expr.False;
  1727. if (numVars != vars.Count)
  1728. throw new AbsHoudiniInternalError(
  1729. string.Format("Got illegal number of arguments ({0}), expected {1}", vars.Count, numVars));
  1730. Expr ret = Expr.True;
  1731. for (int i = 0; i < numVars; i++)
  1732. {
  1733. var sl = new List<Expr>(); sl.Add(vars[i]);
  1734. ret = Expr.And(ret, varVal[i].Gamma(sl));
  1735. }
  1736. return ret;
  1737. }
  1738. private void SetUnderlyingInstance()
  1739. {
  1740. if (underlyingInstance != null) return;
  1741. var tt = typeof(T);
  1742. underlyingInstance = AbstractDomainFactory.GetInstance(tt) as T;
  1743. }
  1744. public bool TypeCheck(List<Type> argTypes, out string msg)
  1745. {
  1746. SetUnderlyingInstance();
  1747. msg = "";
  1748. foreach(var t in argTypes)
  1749. {
  1750. if(!underlyingInstance.TypeCheck(new List<Type>(new Type[] { t }), out msg))
  1751. return false;
  1752. }
  1753. return true;
  1754. }
  1755. }
  1756. public class AbstractDomainFactory
  1757. {
  1758. // Type name -> Instance
  1759. private static Dictionary<string, IAbstractDomain> abstractDomainInstances = new Dictionary<string, IAbstractDomain>();
  1760. private static Dictionary<string, IAbstractDomain> abstractDomainInstancesFriendly = new Dictionary<string, IAbstractDomain>();
  1761. // bitvector operations
  1762. public static Dictionary<int, Function> bvslt = new Dictionary<int, Function>();
  1763. public static void Register(string friendlyName, IAbstractDomain instance)
  1764. {
  1765. var Name = instance.GetType().FullName;
  1766. Debug.Assert(!abstractDomainInstances.ContainsKey(Name));
  1767. abstractDomainInstances.Add(Name, instance);
  1768. abstractDomainInstancesFriendly.Add(friendlyName, instance);
  1769. }
  1770. public static IAbstractDomain GetInstance(System.Type type)
  1771. {
  1772. var Name = type.FullName;
  1773. Debug.Assert(abstractDomainInstances.ContainsKey(Name));
  1774. return abstractDomainInstances[Name] as IAbstractDomain;
  1775. }
  1776. public static IAbstractDomain GetInstance(string friendlyName)
  1777. {
  1778. if (!abstractDomainInstancesFriendly.ContainsKey(friendlyName))
  1779. {
  1780. Console.WriteLine("Domain {0} not found", friendlyName);
  1781. Console.WriteLine("Supported domains are:");
  1782. abstractDomainInstancesFriendly.Keys.Iter(tup => Console.WriteLine(" {0}", tup));
  1783. throw new AbsHoudiniInternalError("Domain not found");
  1784. }
  1785. return abstractDomainInstancesFriendly[friendlyName] as IAbstractDomain;
  1786. }
  1787. public static void Initialize(Program program)
  1788. {
  1789. // Declare abstract domains
  1790. var domains = new List<System.Tuple<string, IAbstractDomain>>(new System.Tuple<string, IAbstractDomain>[] {
  1791. System.Tuple.Create("HoudiniConst", HoudiniConst.GetBottom() as IAbstractDomain),
  1792. System.Tuple.Create("Intervals", new Intervals() as IAbstractDomain),
  1793. System.Tuple.Create("ConstantProp", ConstantProp.GetBottom() as IAbstractDomain),
  1794. System.Tuple.Create("PredicateAbs", new PredicateAbsElem() as IAbstractDomain),
  1795. System.Tuple.Create("ImplicationDomain", ImplicationDomain.GetBottom() as IAbstractDomain),
  1796. System.Tuple.Create("PowDomain", PowDomain.GetBottom() as IAbstractDomain),
  1797. System.Tuple.Create("EqualitiesDomain", EqualitiesDomain.GetBottom() as IAbstractDomain),
  1798. System.Tuple.Create("IA[HoudiniConst]", new IndependentAttribute<HoudiniConst>() as IAbstractDomain),
  1799. System.Tuple.Create("IA[ConstantProp]", new IndependentAttribute<ConstantProp>() as IAbstractDomain),
  1800. System.Tuple.Create("IA[Intervals]", new IndependentAttribute<Intervals>() as IAbstractDomain),
  1801. System.Tuple.Create("IA[PowDomain]", new IndependentAttribute<PowDomain>() as IAbstractDomain),
  1802. });
  1803. domains.Iter(tup => AbstractDomainFactory.Register(tup.Item1, tup.Item2));
  1804. program.Functions.Iter(RegisterFunction);
  1805. }
  1806. private static void RegisterFunction(Function func)
  1807. {
  1808. var attr = QKeyValue.FindStringAttribute(func.Attributes, "bvbuiltin");
  1809. if (attr != null && attr == "bvslt" && func.InParams.Count == 2 && func.InParams[0].TypedIdent.Type.IsBv)
  1810. bvslt.Add(func.InParams[0].TypedIdent.Type.BvBits, func);
  1811. }
  1812. }
  1813. public interface IAbstractDomain
  1814. {
  1815. IAbstractDomain Bottom();
  1816. IAbstractDomain MakeTop(out bool changed);
  1817. IAbstractDomain Join(List<Model.Element> state);
  1818. Expr Gamma(List<Expr> vars);
  1819. bool TypeCheck(List<Type> argTypes, out string msg);
  1820. }
  1821. public class AbstractHoudini
  1822. {
  1823. // Input Program
  1824. Program program;
  1825. // Impl -> VC
  1826. Dictionary<string, VCExpr> impl2VC;
  1827. // Impl -> Vars at end of the impl
  1828. Dictionary<string, List<VCExpr>> impl2EndStateVars;
  1829. // Impl -> (callee,summary pred)
  1830. Dictionary<string, List<Tuple<string, bool, VCExprVar, VCExprNAry>>> impl2CalleeSummaries;
  1831. // pointer to summary class
  1832. ISummaryElement summaryClass;
  1833. // impl -> summary
  1834. Dictionary<string, ISummaryElement> impl2Summary;
  1835. // name -> impl
  1836. Dictionary<string, Implementation> name2Impl;
  1837. // Use Bilateral algorithm
  1838. public static bool UseBilateralAlgo = true;
  1839. public static int iterTimeLimit = -1; // ms
  1840. public static readonly string summaryPredSuffix = "SummaryPred";
  1841. // Essentials: VCGen, Prover, and reporter
  1842. VCGen vcgen;
  1843. ProverInterface prover;
  1844. AbstractHoudiniErrorReporter reporter;
  1845. // Stats
  1846. TimeSpan proverTime;
  1847. int numProverQueries;
  1848. // Produce witness for correctness: can be set programmatically
  1849. public static string WitnessFile = "absHoudiniWitness.bpl";
  1850. public AbstractHoudini(Program program)
  1851. {
  1852. this.program = program;
  1853. this.impl2VC = new Dictionary<string, VCExpr>();
  1854. this.impl2EndStateVars = new Dictionary<string, List<VCExpr>>();
  1855. this.impl2CalleeSummaries = new Dictionary<string, List<Tuple<string, bool, VCExprVar, VCExprNAry>>>();
  1856. this.impl2Summary = new Dictionary<string, ISummaryElement>();
  1857. this.name2Impl = SimpleUtil.nameImplMapping(program);
  1858. if (CommandLineOptions.Clo.ProverKillTime > 0)
  1859. CommandLineOptions.Clo.ProverOptions = CommandLineOptions.Clo.ProverOptions.Concat1(string.Format("TIME_LIMIT={0}", CommandLineOptions.Clo.ProverKillTime));
  1860. this.vcgen = new VCGen(program, CommandLineOptions.Clo.SimplifyLogFilePath, CommandLineOptions.Clo.SimplifyLogFileAppend, new List<Checker>());
  1861. this.prover = ProverInterface.CreateProver(program, CommandLineOptions.Clo.SimplifyLogFilePath, CommandLineOptions.Clo.SimplifyLogFileAppend, -1);
  1862. this.reporter = new AbstractHoudiniErrorReporter();
  1863. this.proverTime = TimeSpan.Zero;
  1864. this.numProverQueries = 0;
  1865. if (CommandLineOptions.Clo.AbstractHoudini == "0")
  1866. UseBilateralAlgo = false;
  1867. }
  1868. public void computeSummaries(ISummaryElement summaryClass)
  1869. {
  1870. // TODO: move this some place else
  1871. PredicateAbs.FindUnsatPairs(prover.VCExprGen, prover);
  1872. this.summaryClass = summaryClass;
  1873. name2Impl.Values.Iter(attachEnsures);
  1874. program.Implementations
  1875. .Iter(impl => impl2Summary.Add(impl.Name, summaryClass.GetFlaseSummary(program, impl)));
  1876. // Build call graph
  1877. var Succ = new Dictionary<Implementation, HashSet<Implementation>>();
  1878. var Pred = new Dictionary<Implementation, HashSet<Implementation>>();
  1879. name2Impl.Values.Iter(impl => Succ.Add(impl, new HashSet<Implementation>()));
  1880. name2Impl.Values.Iter(impl => Pred.Add(impl, new HashSet<Implementation>()));
  1881. foreach (var impl in program.Implementations)
  1882. {
  1883. foreach (var blk in impl.Blocks)
  1884. {
  1885. foreach (var cmd in blk.Cmds.OfType<CallCmd>())
  1886. {
  1887. if (!name2Impl.ContainsKey(cmd.callee)) continue;
  1888. Succ[impl].Add(name2Impl[cmd.callee]);
  1889. Pred[name2Impl[cmd.callee]].Add(impl);
  1890. }
  1891. }
  1892. }
  1893. // Build SCC
  1894. var sccs = new StronglyConnectedComponents<Implementation>(name2Impl.Values,
  1895. new Adjacency<Implementation>(n => Pred[n]),
  1896. new Adjacency<Implementation>(n => Succ[n]));
  1897. sccs.Compute();
  1898. // impl -> priority
  1899. var impl2Priority = new Dictionary<string, int>();
  1900. int p = 0;
  1901. foreach (var scc in sccs)
  1902. {
  1903. foreach (var impl in scc)
  1904. {
  1905. impl2Priority.Add(impl.Name, p);
  1906. p++;
  1907. }
  1908. }
  1909. Inline();
  1910. #region Witness generation setup
  1911. // Create a copy of the program
  1912. var copy = new Dictionary<string, Implementation>();
  1913. if (WitnessFile != null)
  1914. {
  1915. foreach (var impl in program.Implementations)
  1916. {
  1917. var nimpl = new Implementation(Token.NoToken, impl.Name, impl.TypeParameters,
  1918. impl.InParams, impl.OutParams, new List<Variable>(impl.LocVars), new List<Block>());
  1919. foreach (var blk in impl.Blocks)
  1920. {
  1921. var cd = new CodeCopier();
  1922. nimpl.Blocks.Add(new Block(Token.NoToken, blk.Label,
  1923. cd.CopyCmdSeq(blk.Cmds), cd.CopyTransferCmd(blk.TransferCmd)));
  1924. }
  1925. copy.Add(impl.Name, nimpl);
  1926. }
  1927. }
  1928. #endregion
  1929. // Turn off subsumption. Why? Because then I see multiple occurences of the
  1930. // attached ensures in the VC
  1931. CommandLineOptions.Clo.UseSubsumption = CommandLineOptions.SubsumptionOption.Never;
  1932. // Create all VCs
  1933. name2Impl.Values
  1934. .Iter(GenVC);
  1935. // Start the iteration
  1936. var worklist = new SortedSet<Tuple<int, Implementation>>();
  1937. name2Impl.Values
  1938. .Iter(impl => worklist.Add(Tuple.Create(impl2Priority[impl.Name], impl)));
  1939. while (worklist.Any())
  1940. {
  1941. var impl = worklist.First().Item2;
  1942. worklist.Remove(worklist.First());
  1943. var changed = ProcessImpl(impl);
  1944. if (changed)
  1945. {
  1946. Pred[impl].Where(pred => UseBilateralAlgo || pred != impl).Iter(pred => worklist.Add(Tuple.Create(impl2Priority[pred.Name], pred)));
  1947. }
  1948. }
  1949. var allImpls = new SortedSet<Tuple<int, string>>();
  1950. name2Impl.Values.Iter(impl => allImpls.Add(Tuple.Create(impl2Priority[impl.Name], impl.Name)));
  1951. if (CommandLineOptions.Clo.Trace)
  1952. {
  1953. foreach (var tup in allImpls)
  1954. {
  1955. Console.WriteLine("Summary of {0}:", tup.Item2);
  1956. Console.WriteLine("{0}", impl2Summary[tup.Item2]);
  1957. }
  1958. Console.WriteLine("Prover time = {0}", proverTime.TotalSeconds.ToString("F2"));
  1959. Console.WriteLine("Number of prover queries = " + numProverQueries);
  1960. }
  1961. ProduceWitness(copy);
  1962. prover.Close();
  1963. CommandLineOptions.Clo.TheProverFactory.Close();
  1964. }
  1965. public HashSet<string> GetPredicates()
  1966. {
  1967. var ret = new HashSet<string>();
  1968. prover = ProverInterface.CreateProver(program, CommandLineOptions.Clo.SimplifyLogFilePath, CommandLineOptions.Clo.SimplifyLogFileAppend, -1);
  1969. foreach (var tup in impl2Summary)
  1970. {
  1971. var s = tup.Value as PredicateAbs;
  1972. if (s == null) continue;
  1973. ret.UnionWith(s.GetPredicates(program, prover.VCExprGen, prover));
  1974. // debug output
  1975. //Console.WriteLine("Summary of {0}:", tup.Key);
  1976. //Console.WriteLine("{0}", tup.Value);
  1977. }
  1978. prover.Close();
  1979. CommandLineOptions.Clo.TheProverFactory.Close();
  1980. return ret;
  1981. }
  1982. // Obtain the summary expression for a procedure: used programmatically by clients
  1983. // of AbstractHoudini
  1984. public Expr GetSummary(Program program, Procedure proc)
  1985. {
  1986. if (!impl2Summary.ContainsKey(proc.Name))
  1987. return Expr.True;
  1988. var vars = new Dictionary<string, Expr>();
  1989. foreach (var g in program.GlobalVariables)
  1990. vars.Add(g.Name, Expr.Ident(g));
  1991. foreach (var v in proc.InParams.OfType<Variable>())
  1992. vars.Add(v.Name, Expr.Ident(v));
  1993. foreach (var v in proc.OutParams.OfType<Variable>())
  1994. vars.Add(v.Name, Expr.Ident(v));
  1995. return impl2Summary[proc.Name].GetSummaryExpr(
  1996. v => { if (vars.ContainsKey(v)) return vars[v]; else return null; },
  1997. v => { if (vars.ContainsKey(v)) return new OldExpr(Token.NoToken, vars[v]); else return null; });
  1998. }
  1999. public ISummaryElement GetSummaryLowLevel(Procedure proc)
  2000. {
  2001. if (!impl2Summary.ContainsKey(proc.Name)) return null;
  2002. return impl2Summary[proc.Name];
  2003. }
  2004. // Produce a witness that proves that the inferred annotations are correct
  2005. private void ProduceWitness(Dictionary<string, Implementation> copy)
  2006. {
  2007. if (WitnessFile == null)
  2008. return;
  2009. foreach (var proc in program.Procedures)
  2010. {
  2011. var nensures = new List<Ensures>();
  2012. proc.Ensures.OfType<Ensures>()
  2013. .Where(ens => !QKeyValue.FindBoolAttribute(ens.Attributes, "ah") &&
  2014. !QKeyValue.FindBoolAttribute(ens.Attributes, "pre") &&
  2015. !QKeyValue.FindBoolAttribute(ens.Attributes, "post") &&
  2016. QKeyValue.FindStringAttribute(ens.Attributes, "pre") == null &&
  2017. QKeyValue.FindStringAttribute(ens.Attributes, "post") == null)
  2018. .Iter(ens => nensures.Add(ens));
  2019. foreach (Ensures en in nensures)
  2020. en.Attributes = removeAttr("InlineAssume", en.Attributes);
  2021. proc.Ensures = nensures;
  2022. }
  2023. var decls = new List<Declaration>(copy.Values);
  2024. decls.AddRange(program.TopLevelDeclarations.Where(decl => !(decl is Implementation)));
  2025. program.TopLevelDeclarations = decls;
  2026. var name2Proc = new Dictionary<string, Procedure>();
  2027. foreach (var proc in program.Procedures)
  2028. {
  2029. name2Proc.Add(proc.Name, proc);
  2030. if (impl2Summary.ContainsKey(proc.Name))
  2031. {
  2032. var ens = new Ensures(false,
  2033. impl2Summary[proc.Name].GetSummaryExpr(
  2034. new Func<string, Expr>(s => null), new Func<string, Expr>(s => null)));
  2035. ens.Attributes = new QKeyValue(Token.NoToken, "inferred", new List<object>(), ens.Attributes);
  2036. proc.Ensures.Add(ens);
  2037. }
  2038. }
  2039. using (var wt = new TokenTextWriter(WitnessFile, /*pretty=*/ false))
  2040. {
  2041. program.Emit(wt);
  2042. }
  2043. // Replace SummaryPreds with their definition
  2044. foreach (var impl in program.Implementations)
  2045. {
  2046. foreach (var blk in impl.Blocks)
  2047. {
  2048. foreach (var cmd in blk.Cmds.OfType<AssumeCmd>())
  2049. {
  2050. var expr = cmd.Expr as NAryExpr;
  2051. if (expr == null) continue;
  2052. var op = expr.Fun as FunctionCall;
  2053. if (op == null || !op.FunctionName.EndsWith(summaryPredSuffix)) continue;
  2054. var calleeName = op.FunctionName.Substring(0, op.FunctionName.Length - summaryPredSuffix.Length);
  2055. if (!impl2Summary.ContainsKey(calleeName)) continue;
  2056. var callee = name2Impl[calleeName];
  2057. // variable order: globals, ins, outs, modifies
  2058. var forold = new Dictionary<string, Expr>();
  2059. var always = new Dictionary<string, Expr>();
  2060. int i = 0;
  2061. foreach (var g in program.GlobalVariables)
  2062. {
  2063. forold.Add(g.Name, expr.Args[i]);
  2064. always.Add(g.Name, expr.Args[i]);
  2065. i++;
  2066. }
  2067. foreach (var v in callee.InParams.OfType<Variable>())
  2068. {
  2069. always.Add(v.Name, expr.Args[i]);
  2070. i++;
  2071. }
  2072. foreach (var v in callee.OutParams.OfType<Variable>())
  2073. {
  2074. always.Add(v.Name, expr.Args[i]);
  2075. i++;
  2076. }
  2077. foreach (var ie in name2Proc[calleeName].Modifies.OfType<IdentifierExpr>())
  2078. {
  2079. always[ie.Name] = expr.Args[i];
  2080. i++;
  2081. }
  2082. cmd.Expr = impl2Summary[calleeName].GetSummaryExpr(
  2083. v => { if (always.ContainsKey(v)) return always[v]; else return null; },
  2084. v => { if (forold.ContainsKey(v)) return forold[v]; else return null; });
  2085. }
  2086. }
  2087. }
  2088. using (var wt = new TokenTextWriter(WitnessFile, /*pretty=*/ false))
  2089. {
  2090. program.Emit(wt);
  2091. }
  2092. if (CommandLineOptions.Clo.Trace) Console.WriteLine("Witness written to {0}", WitnessFile);
  2093. }
  2094. private QKeyValue removeAttr(string key, QKeyValue attr)
  2095. {
  2096. if (attr == null) return attr;
  2097. if (attr.Key == key) return removeAttr(key, attr.Next);
  2098. attr.Next = removeAttr(key, attr.Next);
  2099. return attr;
  2100. }
  2101. private void Inline()
  2102. {
  2103. if (CommandLineOptions.Clo.InlineDepth < 0)
  2104. return;
  2105. var callGraph = BuildCallGraph();
  2106. foreach (Implementation impl in callGraph.Nodes)
  2107. {
  2108. InlineEnsuresVisitor inlineEnsuresVisitor = new InlineEnsuresVisitor();
  2109. inlineEnsuresVisitor.Visit(impl);
  2110. }
  2111. foreach (Implementation impl in callGraph.Nodes)
  2112. {
  2113. impl.OriginalBlocks = impl.Blocks;
  2114. impl.OriginalLocVars = impl.LocVars;
  2115. }
  2116. foreach (Implementation impl in callGraph.Nodes)
  2117. {
  2118. CommandLineOptions.Inlining savedOption = CommandLineOptions.Clo.ProcedureInlining;
  2119. CommandLineOptions.Clo.ProcedureInlining = CommandLineOptions.Inlining.Spec;
  2120. Inliner.ProcessImplementationForHoudini(program, impl);
  2121. CommandLineOptions.Clo.ProcedureInlining = savedOption;
  2122. }
  2123. foreach (Implementation impl in callGraph.Nodes)
  2124. {
  2125. impl.OriginalBlocks = null;
  2126. impl.OriginalLocVars = null;
  2127. }
  2128. Graph<Implementation> oldCallGraph = callGraph;
  2129. callGraph = new Graph<Implementation>();
  2130. foreach (Implementation impl in oldCallGraph.Nodes)
  2131. {
  2132. callGraph.AddSource(impl);
  2133. }
  2134. foreach (Tuple<Implementation, Implementation> edge in oldCallGraph.Edges)
  2135. {
  2136. callGraph.AddEdge(edge.Item1, edge.Item2);
  2137. }
  2138. int count = CommandLineOptions.Clo.InlineDepth;
  2139. while (count > 0)
  2140. {
  2141. foreach (Implementation impl in oldCallGraph.Nodes)
  2142. {
  2143. List<Implementation> newNodes = new List<Implementation>();
  2144. foreach (Implementation succ in callGraph.Successors(impl))
  2145. {
  2146. newNodes.AddRange(oldCallGraph.Successors(succ));
  2147. }
  2148. foreach (Implementation newNode in newNodes)
  2149. {
  2150. callGraph.AddEdge(impl, newNode);
  2151. }
  2152. }
  2153. count--;
  2154. }
  2155. }
  2156. private Graph<Implementation> BuildCallGraph()
  2157. {
  2158. Graph<Implementation> callGraph = new Graph<Implementation>();
  2159. Dictionary<Procedure, HashSet<Implementation>> procToImpls = new Dictionary<Procedure, HashSet<Implementation>>();
  2160. foreach (var proc in program.Procedures)
  2161. {
  2162. procToImpls[proc] = new HashSet<Implementation>();
  2163. }
  2164. foreach (var impl in program.Implementations)
  2165. {
  2166. if (impl.SkipVerification) continue;
  2167. callGraph.AddSource(impl);
  2168. procToImpls[impl.Proc].Add(impl);
  2169. }
  2170. foreach (var impl in program.Implementations)
  2171. {
  2172. if (impl.SkipVerification) continue;
  2173. foreach (Block b in impl.Blocks)
  2174. {
  2175. foreach (Cmd c in b.Cmds)
  2176. {
  2177. CallCmd cc = c as CallCmd;
  2178. if (cc == null) continue;
  2179. foreach (Implementation callee in procToImpls[cc.Proc])
  2180. {
  2181. callGraph.AddEdge(impl, callee);
  2182. }
  2183. }
  2184. }
  2185. }
  2186. return callGraph;
  2187. }
  2188. private bool ProcessImpl(Implementation impl)
  2189. {
  2190. var ret = false;
  2191. var gen = prover.VCExprGen;
  2192. // construct summaries
  2193. var env = VCExpressionGenerator.True;
  2194. foreach (var tup in impl2CalleeSummaries[impl.Name])
  2195. {
  2196. // Not Bilateral: then reject self predicates
  2197. if (UseBilateralAlgo == false && tup.Item1 == impl.Name)
  2198. continue;
  2199. // Bilateral: only reject self summary
  2200. if (UseBilateralAlgo == true && tup.Item1 == impl.Name && tup.Item2)
  2201. continue;
  2202. var calleeSummary =
  2203. impl2Summary[tup.Item1].GetSummaryExpr(
  2204. GetVarMapping(name2Impl[tup.Item1], tup.Item4), prover.VCExprGen);
  2205. env = gen.AndSimp(env, gen.Eq(tup.Item3, calleeSummary));
  2206. }
  2207. var prev = impl2Summary[impl.Name].Copy();
  2208. var upper = impl2Summary[impl.Name].GetTrueSummary(program, impl);
  2209. var sw = new Stopwatch();
  2210. sw.Start();
  2211. var lowerTime = TimeSpan.Zero;
  2212. while(true)
  2213. {
  2214. var usedLower = true;
  2215. var query = impl2Summary[impl.Name];
  2216. sw.Restart();
  2217. // construct self summaries
  2218. var summaryExpr = VCExpressionGenerator.True;
  2219. foreach (var tup in impl2CalleeSummaries[impl.Name])
  2220. {
  2221. if (UseBilateralAlgo == false && tup.Item1 != impl.Name)
  2222. continue;
  2223. if (UseBilateralAlgo == true && (tup.Item1 != impl.Name || !tup.Item2))
  2224. continue;
  2225. if (UseBilateralAlgo)
  2226. {
  2227. query = query.AbstractConsequence(upper);
  2228. if (query == null) query = impl2Summary[tup.Item1];
  2229. else usedLower = false;
  2230. }
  2231. var ts =
  2232. query.GetSummaryExpr(
  2233. GetVarMapping(name2Impl[tup.Item1], tup.Item4), prover.VCExprGen);
  2234. summaryExpr = gen.AndSimp(summaryExpr, gen.Eq(tup.Item3, ts));
  2235. }
  2236. //Console.WriteLine("Trying summary for {0}: {1}", impl.Name, summaryExpr);
  2237. reporter.model = null;
  2238. var vc = gen.AndSimp(env, summaryExpr);
  2239. vc = gen.Implies(vc, impl2VC[impl.Name]);
  2240. //Console.WriteLine("Checking: {0}", vc);
  2241. if (CommandLineOptions.Clo.Trace)
  2242. Console.WriteLine("Verifying {0} ({1}): {2}", impl.Name, usedLower ? "lower" : "ac", query);
  2243. if (usedLower && lowerTime.TotalMilliseconds >= iterTimeLimit && iterTimeLimit >= 0)
  2244. {
  2245. if (UseBilateralAlgo)
  2246. {
  2247. if (CommandLineOptions.Clo.Trace)
  2248. Console.WriteLine("Timeout/Spaceout while verifying " + impl.Name);
  2249. ret = prev.IsEqual(upper) ? false : true;
  2250. impl2Summary[impl.Name] = upper;
  2251. break;
  2252. }
  2253. else
  2254. {
  2255. if (CommandLineOptions.Clo.Trace)
  2256. Console.WriteLine("Timeout/Spaceout while verifying " + impl.Name);
  2257. var tt = impl2Summary[impl.Name].GetTrueSummary(program, impl);
  2258. ret = prev.IsEqual(tt) ? false : true; ;
  2259. impl2Summary[impl.Name] = tt;
  2260. break;
  2261. }
  2262. }
  2263. var start = DateTime.Now;
  2264. //prover.Push();
  2265. //prover.Assert(gen.Not(vc), true);
  2266. //prover.FlushAxiomsToTheoremProver();
  2267. //prover.Check();
  2268. //ProverInterface.Outcome proverOutcome = prover.CheckOutcome(reporter);
  2269. //prover.Pop();
  2270. prover.BeginCheck(impl.Name, vc, reporter);
  2271. ProverInterface.Outcome proverOutcome = prover.CheckOutcome(reporter);
  2272. var inc = (DateTime.Now - start);
  2273. proverTime += inc;
  2274. numProverQueries++;
  2275. sw.Stop();
  2276. if (usedLower) lowerTime += sw.Elapsed;
  2277. if(CommandLineOptions.Clo.Trace)
  2278. Console.WriteLine("Time taken = " + inc.TotalSeconds.ToString());
  2279. if (UseBilateralAlgo)
  2280. {
  2281. if (proverOutcome == ProverInterface.Outcome.TimeOut || proverOutcome == ProverInterface.Outcome.OutOfMemory)
  2282. {
  2283. if(CommandLineOptions.Clo.Trace)
  2284. Console.WriteLine("Timeout/Spaceout while verifying " + impl.Name);
  2285. ret = prev.IsEqual(upper) ? false : true;
  2286. impl2Summary[impl.Name] = upper;
  2287. break;
  2288. }
  2289. if (reporter.model == null && usedLower)
  2290. break;
  2291. if (reporter.model == null)
  2292. {
  2293. upper.Meet(query);
  2294. }
  2295. else
  2296. {
  2297. var state = CollectState(impl);
  2298. impl2Summary[impl.Name].Join(state, reporter.model);
  2299. ret = true;
  2300. }
  2301. }
  2302. else
  2303. {
  2304. if (proverOutcome == ProverInterface.Outcome.TimeOut || proverOutcome == ProverInterface.Outcome.OutOfMemory)
  2305. {
  2306. if (CommandLineOptions.Clo.Trace)
  2307. Console.WriteLine("Timeout/Spaceout while verifying " + impl.Name);
  2308. var tt = impl2Summary[impl.Name].GetTrueSummary(program, impl);
  2309. ret = prev.IsEqual(tt) ? false : true; ;
  2310. impl2Summary[impl.Name] = tt;
  2311. break;
  2312. }
  2313. if (reporter.model == null)
  2314. break;
  2315. //reporter.model.Write(Console.Out);
  2316. var state = CollectState(impl);
  2317. impl2Summary[impl.Name].Join(state, reporter.model);
  2318. ret = true;
  2319. }
  2320. }
  2321. return ret;
  2322. }
  2323. private Dictionary<string, VCExpr> GetVarMapping(Implementation impl, VCExprNAry summaryPred)
  2324. {
  2325. var ret = new Dictionary<string, VCExpr>();
  2326. var cnt = 0;
  2327. foreach (var g in program.GlobalVariables)
  2328. {
  2329. ret.Add(string.Format("old({0})", g.Name), summaryPred[cnt]);
  2330. cnt++;
  2331. }
  2332. foreach (var v in impl.InParams.OfType<Variable>().Concat(
  2333. impl.OutParams.OfType<Variable>().Concat(
  2334. impl.Proc.Modifies.OfType<IdentifierExpr>().Select(ie => ie.Decl))))
  2335. {
  2336. ret.Add(v.Name, summaryPred[cnt]);
  2337. cnt++;
  2338. }
  2339. // Fill up values of globals that are not modified
  2340. cnt = 0;
  2341. foreach (var g in program.GlobalVariables)
  2342. {
  2343. if (ret.ContainsKey(g.Name)) { cnt++; continue; }
  2344. ret.Add(string.Format("{0}", g.Name), summaryPred[cnt]);
  2345. cnt++;
  2346. }
  2347. // Constants
  2348. foreach (var c in program.Constants)
  2349. {
  2350. var value = prover.Context.BoogieExprTranslator.Translate(Expr.Ident(c));
  2351. ret.Add(string.Format("{0}", c.Name), value);
  2352. ret.Add(string.Format("old({0})", c.Name), value);
  2353. }
  2354. return ret;
  2355. }
  2356. private Dictionary<string, Model.Element> CollectState(Implementation impl)
  2357. {
  2358. var ret = new Dictionary<string, Model.Element>();
  2359. var model = reporter.model;
  2360. var implVars = impl2EndStateVars[impl.Name];
  2361. var cnt = 0;
  2362. foreach (var g in program.GlobalVariables)
  2363. {
  2364. ret.Add(string.Format("old({0})", g.Name), getValue(implVars[cnt], model));
  2365. cnt++;
  2366. }
  2367. foreach (var v in impl.InParams.OfType<Variable>().Concat(
  2368. impl.OutParams.OfType<Variable>().Concat(
  2369. impl.Proc.Modifies.OfType<IdentifierExpr>().Select(ie => ie.Decl))))
  2370. {
  2371. ret.Add(v.Name, getValue(implVars[cnt], model));
  2372. cnt++;
  2373. }
  2374. // Fill up values of globals that are not modified
  2375. cnt = 0;
  2376. foreach (var g in program.GlobalVariables)
  2377. {
  2378. if (ret.ContainsKey(g.Name)) { cnt++; continue; }
  2379. ret.Add(string.Format("{0}", g.Name), getValue(implVars[cnt], model));
  2380. cnt++;
  2381. }
  2382. // Constants
  2383. foreach (var c in program.Constants)
  2384. {
  2385. try
  2386. {
  2387. var value = getValue(prover.Context.BoogieExprTranslator.Translate(Expr.Ident(c)), model);
  2388. ret.Add(string.Format("{0}", c.Name), value);
  2389. ret.Add(string.Format("old({0})", c.Name), value);
  2390. }
  2391. catch (Exception)
  2392. {
  2393. // constant not assigned a value: add a default value
  2394. Model.Element value = null;
  2395. if (c.TypedIdent.Type.IsInt)
  2396. value = model.MkIntElement(0);
  2397. else if (c.TypedIdent.Type.IsBool)
  2398. value = model.MkElement("false");
  2399. ret.Add(string.Format("{0}", c.Name), value);
  2400. ret.Add(string.Format("old({0})", c.Name), value);
  2401. }
  2402. }
  2403. return ret;
  2404. }
  2405. private Model.Element getValue(VCExpr arg, Model model)
  2406. {
  2407. if (arg is VCExprLiteral)
  2408. {
  2409. //return model.GetElement(arg.ToString());
  2410. return model.MkElement(arg.ToString());
  2411. }
  2412. else if (arg is VCExprVar)
  2413. {
  2414. var el = model.TryGetFunc(prover.Context.Lookup(arg as VCExprVar));
  2415. if (el != null)
  2416. {
  2417. Debug.Assert(el.Arity == 0 && el.AppCount == 1);
  2418. return el.Apps.First().Result;
  2419. }
  2420. else
  2421. {
  2422. // Variable not defined; assign arbitrary value
  2423. if (arg.Type.IsBool)
  2424. return model.MkElement("false");
  2425. else if (arg.Type.IsInt)
  2426. return model.MkIntElement(0);
  2427. else
  2428. return null;
  2429. }
  2430. }
  2431. else
  2432. {
  2433. Debug.Assert(false);
  2434. return null;
  2435. }
  2436. }
  2437. private void attachEnsures(Implementation impl)
  2438. {
  2439. List<Variable> functionInterfaceVars = new List<Variable>();
  2440. foreach (Variable v in vcgen.program.GlobalVariables)
  2441. {
  2442. functionInterfaceVars.Add(new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "", v.TypedIdent.Type), true));
  2443. }
  2444. foreach (Variable v in impl.InParams)
  2445. {
  2446. functionInterfaceVars.Add(new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "", v.TypedIdent.Type), true));
  2447. }
  2448. foreach (Variable v in impl.OutParams)
  2449. {
  2450. functionInterfaceVars.Add(new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "", v.TypedIdent.Type), true));
  2451. }
  2452. foreach (IdentifierExpr e in impl.Proc.Modifies)
  2453. {
  2454. if (e.Decl == null) continue;
  2455. functionInterfaceVars.Add(new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "", e.Decl.TypedIdent.Type), true));
  2456. }
  2457. Formal returnVar = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "", Bpl.Type.Bool), false);
  2458. var function = new Function(Token.NoToken, impl.Name + summaryPredSuffix, functionInterfaceVars, returnVar);
  2459. prover.Context.DeclareFunction(function, "");
  2460. List<Expr> exprs = new List<Expr>();
  2461. foreach (Variable v in vcgen.program.GlobalVariables)
  2462. {
  2463. Contract.Assert(v != null);
  2464. exprs.Add(new OldExpr(Token.NoToken, new IdentifierExpr(Token.NoToken, v)));
  2465. }
  2466. foreach (Variable v in impl.Proc.InParams)
  2467. {
  2468. Contract.Assert(v != null);
  2469. exprs.Add(new IdentifierExpr(Token.NoToken, v));
  2470. }
  2471. foreach (Variable v in impl.Proc.OutParams)
  2472. {
  2473. Contract.Assert(v != null);
  2474. exprs.Add(new IdentifierExpr(Token.NoToken, v));
  2475. }
  2476. foreach (IdentifierExpr ie in impl.Proc.Modifies)
  2477. {
  2478. Contract.Assert(ie != null);
  2479. if (ie.Decl == null)
  2480. continue;
  2481. exprs.Add(ie);
  2482. }
  2483. Expr postExpr = new NAryExpr(Token.NoToken, new FunctionCall(function), exprs);
  2484. impl.Proc.Ensures.Add(
  2485. new Ensures(Token.NoToken, false, postExpr, "",
  2486. new QKeyValue(Token.NoToken, "ah", new List<object>(), null)));
  2487. }
  2488. private void GenVC(Implementation impl)
  2489. {
  2490. ModelViewInfo mvInfo;
  2491. Dictionary<int, Absy> label2absy;
  2492. if (CommandLineOptions.Clo.Trace)
  2493. {
  2494. Console.WriteLine("Generating VC of {0}", impl.Name);
  2495. }
  2496. vcgen.ConvertCFG2DAG(impl);
  2497. vcgen.PassifyImpl(impl, out mvInfo);
  2498. var gen = prover.VCExprGen;
  2499. var vcexpr = vcgen.GenerateVC(impl, null, out label2absy, prover.Context);
  2500. // Find the assert
  2501. impl2EndStateVars.Add(impl.Name, new List<VCExpr>());
  2502. var found = false;
  2503. var assertId = -1;
  2504. foreach (var blk in impl.Blocks)
  2505. {
  2506. foreach (var cmd in blk.Cmds.OfType<AssertCmd>())
  2507. {
  2508. if (SimpleUtil.isAssertTrue(cmd)) continue;
  2509. var nary = cmd.Expr as NAryExpr;
  2510. if (nary == null) continue;
  2511. var pred = nary.Fun as FunctionCall;
  2512. if (pred == null || pred.FunctionName != (impl.Name + (AbstractHoudini.summaryPredSuffix)))
  2513. continue;
  2514. Debug.Assert(!found);
  2515. found = true;
  2516. assertId = cmd.UniqueId;
  2517. //Console.WriteLine("assert cmd id: {0}", cmd.UniqueId);
  2518. nary.Args.OfType<Expr>()
  2519. .Iter(expr => impl2EndStateVars[impl.Name].Add(prover.Context.BoogieExprTranslator.Translate(expr)));
  2520. }
  2521. }
  2522. // It is possible that no assert is found in the procedure. It happens when the
  2523. // procedure doesn't return.
  2524. //Debug.Assert(found);
  2525. // Grab summary predicates
  2526. var visitor = new FindSummaryPred(prover.VCExprGen, assertId);
  2527. vcexpr = visitor.Mutate(vcexpr, true);
  2528. // Create a macro so that the VC can sit with the theorem prover
  2529. Macro macro = new Macro(Token.NoToken, impl.Name + "Macro", new List<Variable>(), new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "", Bpl.Type.Bool), false));
  2530. prover.DefineMacro(macro, vcexpr);
  2531. // Store VC
  2532. impl2VC.Add(impl.Name, gen.Function(macro));
  2533. //Console.WriteLine("VC of {0}: {1}", impl.Name, vcexpr);
  2534. // check sanity: only one predicate for self-summary
  2535. // (There may be none when the procedure doesn't return)
  2536. Debug.Assert(visitor.summaryPreds.Count(tup => tup.Item2) <= 1);
  2537. impl2CalleeSummaries.Add(impl.Name, new List<Tuple<string, bool, VCExprVar, VCExprNAry>>());
  2538. visitor.summaryPreds.Iter(tup => impl2CalleeSummaries[impl.Name].Add(tup));
  2539. }
  2540. }
  2541. public interface ISummaryElement
  2542. {
  2543. ISummaryElement Copy();
  2544. ISummaryElement GetFlaseSummary(Program program, Implementation impl);
  2545. void Join(Dictionary<string, Model.Element> state, Model model);
  2546. VCExpr GetSummaryExpr(Dictionary<string, VCExpr> incarnations, VCExpressionGenerator gen);
  2547. Expr GetSummaryExpr(Func<string, Expr> always, Func<string, Expr> forold);
  2548. // For Bilateral
  2549. ISummaryElement GetTrueSummary(Program program, Implementation impl);
  2550. void Meet(ISummaryElement other);
  2551. bool IsEqual(ISummaryElement other);
  2552. ISummaryElement AbstractConsequence(ISummaryElement upper);
  2553. }
  2554. public class ConstantVal : ISummaryElement
  2555. {
  2556. Program program;
  2557. Implementation impl;
  2558. // var -> const set
  2559. Dictionary<string, HashSet<int>> val;
  2560. // set of vars
  2561. HashSet<Variable> vars;
  2562. public static readonly int MAX = 3;
  2563. public ConstantVal()
  2564. {
  2565. // this is just a place holder
  2566. val = new Dictionary<string, HashSet<int>>();
  2567. vars = new HashSet<Variable>();
  2568. }
  2569. private ConstantVal(Program program, Implementation impl)
  2570. {
  2571. this.program = program;
  2572. this.impl = impl;
  2573. this.val = new Dictionary<string, HashSet<int>>();
  2574. vars = new HashSet<Variable>();
  2575. impl.Proc.Modifies
  2576. .OfType<IdentifierExpr>()
  2577. .Select(ie => ie.Decl)
  2578. .Where(v => v.TypedIdent.Type.IsInt)
  2579. .Iter(v => vars.Add(v));
  2580. impl.OutParams.OfType<Variable>()
  2581. .Where(v => v.TypedIdent.Type.IsInt)
  2582. .Iter(v => vars.Add(v));
  2583. vars.Iter(v => val.Add(v.Name, null));
  2584. }
  2585. public void Join(Dictionary<string, Model.Element> state, Model model)
  2586. {
  2587. foreach (var vv in vars)
  2588. {
  2589. var v = vv.Name;
  2590. var newv = state[v].AsInt();
  2591. var oldv = val[v];
  2592. if (oldv == null)
  2593. {
  2594. val[v] = new HashSet<int>();
  2595. val[v].Add(newv);
  2596. }
  2597. else if(oldv.Count > 0)
  2598. {
  2599. val[v].Add(newv);
  2600. if (val[v].Count > MAX)
  2601. val[v] = new HashSet<int>();
  2602. }
  2603. }
  2604. }
  2605. public VCExpr GetSummaryExpr(Dictionary<string, VCExpr> incarnations, VCExpressionGenerator gen)
  2606. {
  2607. VCExpr ret = VCExpressionGenerator.True;
  2608. if (val.Values.Any(v => v == null))
  2609. return VCExpressionGenerator.False;
  2610. foreach (var v in vars)
  2611. {
  2612. var consts = val[v.Name];
  2613. Debug.Assert(consts != null);
  2614. if (consts.Count == 0)
  2615. continue;
  2616. var vexpr = VCExpressionGenerator.False;
  2617. consts.Iter(c => vexpr = gen.OrSimp(vexpr, gen.Eq(incarnations[v.Name], gen.Integer(Microsoft.Basetypes.BigNum.FromInt(c)))));
  2618. ret = gen.AndSimp(ret, vexpr);
  2619. }
  2620. return ret;
  2621. }
  2622. public override string ToString()
  2623. {
  2624. var ret = "true";
  2625. if (val.Values.Any(v => v == null))
  2626. return "false";
  2627. foreach (var v in vars)
  2628. {
  2629. var consts = val[v.Name];
  2630. Debug.Assert(consts != null);
  2631. if (consts.Count == 0)
  2632. continue;
  2633. var vexpr = "false";
  2634. consts.Iter(c => vexpr =
  2635. string.Format("{0} OR ({1} == {2})", vexpr, v.Name, c));
  2636. ret = string.Format("{0} AND ({1})", ret, vexpr);
  2637. }
  2638. return ret;
  2639. }
  2640. public ISummaryElement GetFlaseSummary(Program program, Implementation impl)
  2641. {
  2642. return new ConstantVal(program, impl);
  2643. }
  2644. #region ISummaryElement (Bilateral) Members
  2645. public ISummaryElement GetTrueSummary(Program program, Implementation impl)
  2646. {
  2647. throw new NotImplementedException();
  2648. }
  2649. public void Meet(ISummaryElement other)
  2650. {
  2651. throw new NotImplementedException();
  2652. }
  2653. public bool IsEqual(ISummaryElement other)
  2654. {
  2655. throw new NotImplementedException();
  2656. }
  2657. public ISummaryElement AbstractConsequence(ISummaryElement upper)
  2658. {
  2659. throw new NotImplementedException();
  2660. }
  2661. #endregion
  2662. #region ISummaryElement Members
  2663. public Expr GetSummaryExpr(Func<string, Expr> always, Func<string, Expr> forold)
  2664. {
  2665. throw new NotImplementedException();
  2666. }
  2667. #endregion
  2668. #region ISummaryElement Members
  2669. public ISummaryElement Copy()
  2670. {
  2671. throw new NotImplementedException();
  2672. }
  2673. #endregion
  2674. }
  2675. public class NamedExpr
  2676. {
  2677. public string name;
  2678. public Expr expr;
  2679. public NamedExpr(string name, Expr expr)
  2680. {
  2681. this.name = name;
  2682. this.expr = expr;
  2683. }
  2684. public NamedExpr(Expr expr)
  2685. {
  2686. this.name = null;
  2687. this.expr = expr;
  2688. }
  2689. public override string ToString()
  2690. {
  2691. if (name != null)
  2692. return name;
  2693. return expr.ToString();
  2694. }
  2695. }
  2696. public class PredicateAbs : ISummaryElement
  2697. {
  2698. public static Dictionary<string, List<NamedExpr>> PrePreds { get; private set; }
  2699. public static Dictionary<string, HashSet<int>> PosPrePreds { get; private set; }
  2700. public static Dictionary<string, List<NamedExpr>> PostPreds { get; private set; }
  2701. public static Dictionary<Tuple<string, int>, List<PredicateAbsDisjunct>> UpperCandidates;
  2702. private static HashSet<string> boolConstants;
  2703. // {proc, pred-pair} -> polariry
  2704. public static HashSet<Tuple<string, int, int, bool, bool>> unsatPrePredPairs;
  2705. public static HashSet<Tuple<string, int, int, bool, bool>> unsatPostPredPairs;
  2706. // Temporary: used during eval
  2707. private static Model model = null;
  2708. string procName;
  2709. PredicateAbsDisjunct[] value;
  2710. bool isFalse;
  2711. public PredicateAbs(string procName)
  2712. {
  2713. this.procName = procName;
  2714. isFalse = true;
  2715. value = new PredicateAbsDisjunct[PostPreds[this.procName].Count];
  2716. for (int i = 0; i < PostPreds[this.procName].Count; i++) value[i] = null;
  2717. }
  2718. public static void Initialize(Program program)
  2719. {
  2720. PrePreds = new Dictionary<string, List<NamedExpr>>();
  2721. PostPreds = new Dictionary<string, List<NamedExpr>>();
  2722. PosPrePreds = new Dictionary<string, HashSet<int>>();
  2723. boolConstants = new HashSet<string>();
  2724. UpperCandidates = new Dictionary<Tuple<string, int>, List<PredicateAbsDisjunct>>();
  2725. program.Constants
  2726. .Where(c => c.TypedIdent.Type.IsBool)
  2727. .Iter(c => boolConstants.Add(c.Name));
  2728. // Add template pre-post to all procedures
  2729. var preT = new List<NamedExpr>();
  2730. var postT = new List<NamedExpr>();
  2731. var posPreT = new HashSet<int>();
  2732. var tempP = new HashSet<Procedure>();
  2733. foreach (var proc in
  2734. program.Procedures
  2735. .Where(proc => QKeyValue.FindBoolAttribute(proc.Attributes, "template")))
  2736. {
  2737. tempP.Add(proc);
  2738. foreach (var ens in proc.Ensures.OfType<Ensures>())
  2739. {
  2740. var pos = QKeyValue.FindBoolAttribute(ens.Attributes, "positive");
  2741. if (QKeyValue.FindBoolAttribute(ens.Attributes, "pre"))
  2742. {
  2743. preT.Add(new NamedExpr(null, ens.Condition));
  2744. if (pos) posPreT.Add(preT.Count - 1);
  2745. }
  2746. if (QKeyValue.FindBoolAttribute(ens.Attributes, "post"))
  2747. postT.Add(new NamedExpr(null, ens.Condition));
  2748. var s = QKeyValue.FindStringAttribute(ens.Attributes, "pre");
  2749. if (s != null)
  2750. {
  2751. preT.Add(new NamedExpr(s, ens.Condition));
  2752. if (pos) posPreT.Add(preT.Count - 1);
  2753. }
  2754. s = QKeyValue.FindStringAttribute(ens.Attributes, "post");
  2755. if (s != null)
  2756. postT.Add(new NamedExpr(s, ens.Condition));
  2757. }
  2758. }
  2759. program.RemoveTopLevelDeclarations(decl => tempP.Contains(decl));
  2760. var upperPreds = new Dictionary<string, List<Expr>>();
  2761. foreach (var impl in program.Implementations)
  2762. {
  2763. PrePreds.Add(impl.Name, new List<NamedExpr>());
  2764. PostPreds.Add(impl.Name, new List<NamedExpr>());
  2765. PosPrePreds.Add(impl.Name, new HashSet<int>());
  2766. // Add "false" as the first post predicate
  2767. //PostPreds[impl.Name].Add(new NamedExpr(Expr.False));
  2768. preT.Iter(e => PrePreds[impl.Name].Add(e));
  2769. postT.Iter(e => PostPreds[impl.Name].Add(e));
  2770. PosPrePreds[impl.Name].UnionWith(posPreT);
  2771. // Pick up per-procedure pre-post
  2772. var nens = new List<Ensures>();
  2773. foreach (var ens in impl.Proc.Ensures.OfType<Ensures>())
  2774. {
  2775. string s = null;
  2776. var pos = QKeyValue.FindBoolAttribute(ens.Attributes, "positive");
  2777. if (QKeyValue.FindBoolAttribute(ens.Attributes, "pre"))
  2778. {
  2779. PrePreds[impl.Name].Add(new NamedExpr(ens.Condition));
  2780. PosPrePreds[impl.Name].Add(PrePreds[impl.Name].Count - 1);
  2781. }
  2782. else if (QKeyValue.FindBoolAttribute(ens.Attributes, "post"))
  2783. {
  2784. PostPreds[impl.Name].Add(new NamedExpr(ens.Condition));
  2785. }
  2786. else if ((s = QKeyValue.FindStringAttribute(ens.Attributes, "pre")) != null)
  2787. {
  2788. PrePreds[impl.Name].Add(new NamedExpr(s, ens.Condition));
  2789. PosPrePreds[impl.Name].Add(PrePreds[impl.Name].Count - 1);
  2790. }
  2791. else if ((s = QKeyValue.FindStringAttribute(ens.Attributes, "post")) != null)
  2792. {
  2793. PostPreds[impl.Name].Add(new NamedExpr(s, ens.Condition));
  2794. }
  2795. else if (QKeyValue.FindBoolAttribute(ens.Attributes, "upper"))
  2796. {
  2797. var key = impl.Name;
  2798. if (!upperPreds.ContainsKey(key))
  2799. upperPreds.Add(key, new List<Expr>());
  2800. upperPreds[key].Add(ens.Condition);
  2801. }
  2802. else
  2803. {
  2804. nens.Add(ens);
  2805. }
  2806. }
  2807. impl.Proc.Ensures = nens;
  2808. }
  2809. foreach (var tup in upperPreds)
  2810. {
  2811. var procName = tup.Key;
  2812. var candidates = tup.Value;
  2813. if (!candidates.Any()) continue;
  2814. var strToPost = new Dictionary<string, int>();
  2815. for (int i = 0; i < PostPreds[procName].Count; i++)
  2816. {
  2817. strToPost.Add(PostPreds[procName][i].expr.ToString(), i);
  2818. }
  2819. foreach (var expr in candidates)
  2820. {
  2821. if (strToPost.ContainsKey(expr.ToString()))
  2822. {
  2823. var key = Tuple.Create(procName, strToPost[expr.ToString()]);
  2824. if (!UpperCandidates.ContainsKey(key))
  2825. UpperCandidates.Add(key, new List<PredicateAbsDisjunct>());
  2826. UpperCandidates[key].Add(new PredicateAbsDisjunct(true, procName));
  2827. }
  2828. else
  2829. {
  2830. // Try parsing the expression as (pre-conjunct ==> post-pred)
  2831. var parsed = ParseExpr(expr, procName);
  2832. if (parsed != null && strToPost.ContainsKey(parsed.Item2.ToString()))
  2833. {
  2834. var key = Tuple.Create(procName, strToPost[parsed.Item2.ToString()]);
  2835. if (!UpperCandidates.ContainsKey(key))
  2836. UpperCandidates.Add(key, new List<PredicateAbsDisjunct>());
  2837. UpperCandidates[key].Add(parsed.Item1);
  2838. }
  2839. }
  2840. }
  2841. }
  2842. //Console.WriteLine("Running Abstract Houdini");
  2843. //PostPreds.Iter(expr => Console.WriteLine("\tPost: {0}", expr));
  2844. //PrePreds.Iter(expr => Console.WriteLine("\tPre: {0}", expr));
  2845. }
  2846. // Try parsing the expression as (pre-conjunct ==> post-pred)
  2847. private static Tuple<PredicateAbsDisjunct, Expr> ParseExpr(Expr expr, string procName)
  2848. {
  2849. Expr postExpr = null;
  2850. Expr preExpr = null;
  2851. // Decompose outer Implies
  2852. var nexpr = expr as NAryExpr;
  2853. if (nexpr != null && (nexpr.Fun is BinaryOperator)
  2854. && (nexpr.Fun as BinaryOperator).Op == BinaryOperator.Opcode.Imp
  2855. && (nexpr.Args.Count == 2))
  2856. {
  2857. postExpr = nexpr.Args[1];
  2858. preExpr = nexpr.Args[0];
  2859. }
  2860. else
  2861. {
  2862. if(CommandLineOptions.Clo.Trace) Console.WriteLine("Failed to parse {0} (ignoring)", expr);
  2863. return null;
  2864. }
  2865. var atoms = DecomposeOuterAnd(preExpr);
  2866. var pos = new HashSet<int>();
  2867. var neg = new HashSet<int>();
  2868. foreach (var atom in atoms)
  2869. {
  2870. var index = PrePreds[procName].FindIndex(ne => ne.expr.ToString() == atom.ToString());
  2871. if (index == -1)
  2872. {
  2873. index = PrePreds[procName].FindIndex(ne => Expr.Not(ne.expr).ToString() == atom.ToString());
  2874. if (index == -1)
  2875. {
  2876. if(CommandLineOptions.Clo.Trace) Console.WriteLine("Failed to parse {0} (ignoring)", atom);
  2877. return null;
  2878. }
  2879. else
  2880. {
  2881. neg.Add(index);
  2882. }
  2883. }
  2884. else
  2885. {
  2886. pos.Add(index);
  2887. }
  2888. }
  2889. var conj = new PredicateAbsConjunct(pos, neg, procName);
  2890. var conjls = new List<PredicateAbsConjunct>();
  2891. conjls.Add(conj);
  2892. return Tuple.Create(new PredicateAbsDisjunct(conjls, procName), postExpr);
  2893. }
  2894. // blah && blah ==> {blah, blah}
  2895. static IEnumerable<Expr> DecomposeOuterAnd(Expr expr)
  2896. {
  2897. var ret = new List<Expr>();
  2898. var nexpr = expr as NAryExpr;
  2899. if (nexpr == null
  2900. || !(nexpr.Fun is BinaryOperator)
  2901. || (nexpr.Fun as BinaryOperator).Op != BinaryOperator.Opcode.And)
  2902. {
  2903. ret.Add(expr);
  2904. }
  2905. else
  2906. {
  2907. foreach (Expr a in nexpr.Args)
  2908. ret.AddRange(DecomposeOuterAnd(a));
  2909. }
  2910. return ret;
  2911. }
  2912. private Model.Element Eval(Expr expr, Dictionary<string, Model.Element> state)
  2913. {
  2914. if (expr is LiteralExpr)
  2915. {
  2916. return ToElem((expr as LiteralExpr).Val);
  2917. }
  2918. if (expr is IdentifierExpr)
  2919. {
  2920. return LookupVariable((expr as IdentifierExpr).Name, state, false);
  2921. }
  2922. if (expr is OldExpr)
  2923. {
  2924. var ide = (expr as OldExpr).Expr as IdentifierExpr;
  2925. Debug.Assert(ide != null);
  2926. return LookupVariable(ide.Name, state, true);
  2927. }
  2928. if (expr is NAryExpr)
  2929. {
  2930. var nary = expr as NAryExpr;
  2931. if (nary.Fun is UnaryOperator)
  2932. {
  2933. return ToElem((nary.Fun as UnaryOperator).Evaluate(ToValue(Eval(nary.Args[0], state))));
  2934. }
  2935. if (nary.Fun is BinaryOperator)
  2936. {
  2937. return ToElem((nary.Fun as BinaryOperator).Evaluate(ToValue(Eval(nary.Args[0], state)), ToValue(Eval(nary.Args[1], state))));
  2938. }
  2939. if (nary.Fun is MapSelect && nary.Args.Count == 2)
  2940. {
  2941. var index = Eval(nary.Args[1], state);
  2942. var map = Eval(nary.Args[0], state) as Model.Array;
  2943. Debug.Assert(map != null, "Variable of map type must have an Array-typed value");
  2944. var ret = map.Value.TryEval(index as Model.Element);
  2945. if (ret == null) ret = map.Value.Else;
  2946. Debug.Assert(ret != null);
  2947. return ret;
  2948. }
  2949. Debug.Assert(false, "No other op is handled");
  2950. }
  2951. throw new NotImplementedException(string.Format("Expr of type {0} is not handled", expr.GetType().ToString()));
  2952. }
  2953. private Model.Element LookupVariable(string v, Dictionary<string, Model.Element> state, bool tryOld)
  2954. {
  2955. if (tryOld)
  2956. {
  2957. var oldv = string.Format("old({0})", v);
  2958. if (state.ContainsKey(oldv))
  2959. {
  2960. return state[oldv];
  2961. }
  2962. throw new AbsHoudiniInternalError("Cannot handle this case");
  2963. }
  2964. if (state.ContainsKey(v))
  2965. {
  2966. return state[v];
  2967. }
  2968. /*
  2969. if (boolConstants.Contains(v))
  2970. {
  2971. // value of this constant is immaterial, return true
  2972. return model.MkElement("true");
  2973. }
  2974. */
  2975. throw new AbsHoudiniInternalError("Cannot handle this case");
  2976. }
  2977. private static VCExpr ToVcVar(string v, Dictionary<string, VCExpr> incarnations, bool tryOld)
  2978. {
  2979. if (tryOld)
  2980. {
  2981. var oldv = string.Format("old({0})", v);
  2982. if (incarnations.ContainsKey(oldv))
  2983. {
  2984. return incarnations[oldv];
  2985. }
  2986. throw new AbsHoudiniInternalError("Cannot handle this case");
  2987. }
  2988. if (incarnations.ContainsKey(v))
  2989. {
  2990. return incarnations[v];
  2991. }
  2992. throw new AbsHoudiniInternalError("Cannot handle this case");
  2993. }
  2994. public static void FindUnsatPairs(VCExpressionGenerator gen, ProverInterface prover)
  2995. {
  2996. unsatPrePredPairs = new HashSet<Tuple<string, int, int, bool, bool>>();
  2997. unsatPostPredPairs = new HashSet<Tuple<string, int, int, bool, bool>>();
  2998. var cachePos = new HashSet<Tuple<string, string>>();
  2999. var cacheNeg = new HashSet<Tuple<string, string>>();
  3000. var record = new Action<object, string, int, int, bool, bool>(
  3001. (map, proc, e1, e2, p1, p2) => {
  3002. var key = Tuple.Create(proc, e1, e2, p1, p2);
  3003. if (map == PrePreds)
  3004. unsatPrePredPairs.Add(key);
  3005. else
  3006. unsatPostPredPairs.Add(key);
  3007. }
  3008. );
  3009. var predMaps = new List<Dictionary<string, List<NamedExpr>>>();
  3010. predMaps.Add(PrePreds); predMaps.Add(PostPreds);
  3011. foreach (var map in predMaps)
  3012. {
  3013. foreach (var proc in map.Keys)
  3014. {
  3015. for (int i = 0; i < 2 * map[proc].Count(); i++)
  3016. {
  3017. var p1 = (i % 2); // polarity
  3018. var e1 = map[proc][i / 2].expr;
  3019. if (p1 == 0) e1 = Expr.Not(e1);
  3020. for (int j = 2 * ((i / 2) + 1); j < 2 * map[proc].Count(); j++)
  3021. {
  3022. var p2 = (j % 2); // polarity
  3023. var e2 = map[proc][j / 2].expr;
  3024. if (p2 == 0) e2 = Expr.Not(e2);
  3025. var key = Tuple.Create(e1.ToString(), e2.ToString());
  3026. if (cachePos.Contains(key))
  3027. {
  3028. record(map, proc, i / 2, j / 2, p1 == 1, p2 == 1);
  3029. continue;
  3030. }
  3031. else if (cacheNeg.Contains(key))
  3032. {
  3033. continue;
  3034. }
  3035. if (!CheckIfUnsat(e1, e2, gen, prover))
  3036. {
  3037. cacheNeg.Add(key);
  3038. continue;
  3039. }
  3040. cachePos.Add(key);
  3041. record(map, proc, i / 2, j / 2, p1 == 1, p2 == 1);
  3042. if (CommandLineOptions.Clo.Trace)
  3043. Console.WriteLine("Proved UNSAT: {0} {1}", e1, e2);
  3044. }
  3045. }
  3046. }
  3047. }
  3048. }
  3049. // Is a ^ b UNSAT?
  3050. private static bool CheckIfUnsat(Expr a, Expr b, VCExpressionGenerator gen, ProverInterface prover)
  3051. {
  3052. var gatherLitA = new GatherLiterals();
  3053. var gatherLitB = new GatherLiterals();
  3054. gatherLitA.Visit(a);
  3055. gatherLitB.Visit(b);
  3056. var seta = new HashSet<Variable>();
  3057. var setb = new HashSet<Variable>();
  3058. gatherLitA.literals.Iter(tup => seta.Add(tup.Item1));
  3059. gatherLitB.literals.Iter(tup => setb.Add(tup.Item1));
  3060. seta.IntersectWith(setb);
  3061. if (!seta.Any()) return false;
  3062. // Create fresh variables
  3063. return CheckIfUnsat(Expr.And(a, b), gen, prover);
  3064. }
  3065. // Is a UNSAT?
  3066. private static bool CheckIfUnsat(Expr a, VCExpressionGenerator gen, ProverInterface prover)
  3067. {
  3068. var gatherLitA = new GatherLiterals();
  3069. gatherLitA.Visit(a);
  3070. // Create fresh variables
  3071. var counter = 0;
  3072. var incarnations = new Dictionary<string, VCExpr>();
  3073. foreach (var literal in gatherLitA.literals)
  3074. {
  3075. if (incarnations.ContainsKey(literal.Item2.ToString()))
  3076. continue;
  3077. //if(!literal.Item1.TypedIdent.Type.IsInt && !literal.Item1.TypedIdent.Type.IsBool)
  3078. var v = gen.Variable("UNSATCheck" + counter, literal.Item1.TypedIdent.Type);
  3079. incarnations.Add(literal.Item2.ToString(), v);
  3080. counter++;
  3081. }
  3082. var vc1 = ToVcExpr(a, incarnations, gen);
  3083. var vc = gen.LabelPos("Temp", vc1);
  3084. // check
  3085. prover.AssertAxioms();
  3086. prover.Push();
  3087. prover.Assert(vc, true);
  3088. prover.Check();
  3089. var outcome = prover.CheckOutcomeCore(new AbstractHoudiniErrorReporter());
  3090. prover.Pop();
  3091. if (outcome == ProverInterface.Outcome.Valid)
  3092. return true;
  3093. return false;
  3094. }
  3095. class GatherLiterals : ReadOnlyVisitor
  3096. {
  3097. public List<Tuple<Variable, Expr>> literals;
  3098. bool inOld;
  3099. public GatherLiterals()
  3100. {
  3101. literals = new List<Tuple<Variable, Expr>>();
  3102. inOld = false;
  3103. }
  3104. public override Expr VisitOldExpr(OldExpr node)
  3105. {
  3106. var prev = inOld;
  3107. inOld = true;
  3108. var ret = base.VisitOldExpr(node);
  3109. inOld = prev;
  3110. return ret;
  3111. }
  3112. public override Expr VisitIdentifierExpr(IdentifierExpr node)
  3113. {
  3114. if (inOld)
  3115. literals.Add(Tuple.Create(node.Decl, new OldExpr(Token.NoToken, node) as Expr));
  3116. else
  3117. literals.Add(Tuple.Create(node.Decl, node as Expr));
  3118. return node;
  3119. }
  3120. }
  3121. private object ToValue(Model.Element elem)
  3122. {
  3123. if (elem is Model.Integer)
  3124. {
  3125. return Microsoft.Basetypes.BigNum.FromInt((elem as Model.Integer).AsInt());
  3126. }
  3127. if (elem is Model.Boolean)
  3128. {
  3129. return (elem as Model.Boolean).Value;
  3130. }
  3131. if (elem is Model.DatatypeValue && (elem as Model.DatatypeValue).Arguments.Length == 1 &&
  3132. (elem as Model.DatatypeValue).ConstructorName == "-" &&
  3133. (elem as Model.DatatypeValue).Arguments[0] is Model.Integer)
  3134. {
  3135. // negative number as "-" @ int
  3136. return Microsoft.Basetypes.BigNum.FromInt(-1 * ((elem as Model.DatatypeValue).Arguments[0] as Model.Integer).AsInt());
  3137. }
  3138. throw new NotImplementedException("Cannot yet handle this Model.Element type");
  3139. }
  3140. private Model.Element ToElem(object val)
  3141. {
  3142. if (val is bool || val is int || val is Basetypes.BigNum)
  3143. return model.MkElement(val.ToString());
  3144. throw new NotImplementedException("Cannot yet handle this value type");
  3145. }
  3146. // replace v by old(v)
  3147. private static Expr MakeOld(Expr expr)
  3148. {
  3149. var substalways = new Substitution(v => new OldExpr(Token.NoToken, Expr.Ident(v)));
  3150. var substold = new Substitution(v => Expr.Ident(v));
  3151. return Substituter.ApplyReplacingOldExprs(substalways, substold, expr);
  3152. }
  3153. private static Expr ToExpr(Expr expr, Func<string, Expr> always, Func<string, Expr> forold)
  3154. {
  3155. var substalways = new Substitution(v =>
  3156. {
  3157. var ret = always(v.Name);
  3158. if (ret != null) return ret;
  3159. else return Expr.Ident(v);
  3160. });
  3161. var substold = new Substitution(v =>
  3162. {
  3163. var ret = forold(v.Name);
  3164. if (ret != null) return ret;
  3165. else return new OldExpr(Token.NoToken, Expr.Ident(v));
  3166. });
  3167. return Substituter.ApplyReplacingOldExprs(substalways, substold, expr);
  3168. }
  3169. private static VCExpr ToVcExpr(Expr expr, Dictionary<string, VCExpr> incarnations, VCExpressionGenerator gen)
  3170. {
  3171. if (expr is LiteralExpr)
  3172. {
  3173. var val = (expr as LiteralExpr).Val;
  3174. if (val is bool)
  3175. {
  3176. if ((bool)val)
  3177. {
  3178. return VCExpressionGenerator.True;
  3179. }
  3180. else
  3181. {
  3182. return VCExpressionGenerator.False;
  3183. }
  3184. }
  3185. else if (val is Microsoft.Basetypes.BigNum)
  3186. {
  3187. return gen.Integer((Microsoft.Basetypes.BigNum)val);
  3188. }
  3189. throw new NotImplementedException("Cannot handle literals of this type");
  3190. }
  3191. if (expr is IdentifierExpr)
  3192. {
  3193. return ToVcVar((expr as IdentifierExpr).Name, incarnations, false);
  3194. }
  3195. if (expr is OldExpr)
  3196. {
  3197. var ide = (expr as OldExpr).Expr as IdentifierExpr;
  3198. Debug.Assert(ide != null);
  3199. return ToVcVar(ide.Name, incarnations, true);
  3200. }
  3201. if (expr is NAryExpr)
  3202. {
  3203. var nary = expr as NAryExpr;
  3204. if (nary.Fun is UnaryOperator)
  3205. {
  3206. if ((nary.Fun as UnaryOperator).Op == UnaryOperator.Opcode.Not)
  3207. return gen.Not(ToVcExpr(nary.Args[0], incarnations, gen));
  3208. else if ((nary.Fun as UnaryOperator).Op == UnaryOperator.Opcode.Neg)
  3209. return gen.Function(VCExpressionGenerator.SubIOp, gen.Integer(Basetypes.BigNum.FromInt(0)), ToVcExpr(nary.Args[0], incarnations, gen));
  3210. else
  3211. Debug.Assert(false, "No other unary op is handled");
  3212. }
  3213. if (nary.Fun is BinaryOperator)
  3214. {
  3215. return gen.Function(Translate(nary.Fun as BinaryOperator), ToVcExpr(nary.Args[0], incarnations, gen), ToVcExpr(nary.Args[1], incarnations, gen));
  3216. }
  3217. if (nary.Fun is MapSelect && nary.Args.Count == 2)
  3218. {
  3219. return gen.Select(ToVcExpr(nary.Args[0], incarnations, gen), ToVcExpr(nary.Args[1], incarnations, gen));
  3220. }
  3221. Debug.Assert(false, "No other op is handled");
  3222. }
  3223. throw new NotImplementedException(string.Format("Expr of type {0} is not handled", expr.GetType().ToString()));
  3224. }
  3225. private static VCExprOp Translate(BinaryOperator op)
  3226. {
  3227. switch (op.Op)
  3228. {
  3229. case BinaryOperator.Opcode.Add:
  3230. return VCExpressionGenerator.AddIOp;
  3231. case BinaryOperator.Opcode.Sub:
  3232. return VCExpressionGenerator.SubIOp;
  3233. case BinaryOperator.Opcode.Mul:
  3234. return VCExpressionGenerator.MulIOp;
  3235. case BinaryOperator.Opcode.Div:
  3236. return VCExpressionGenerator.DivIOp;
  3237. case BinaryOperator.Opcode.Mod:
  3238. return VCExpressionGenerator.ModOp;
  3239. case BinaryOperator.Opcode.Eq:
  3240. case BinaryOperator.Opcode.Iff:
  3241. // we don't distinguish between equality and equivalence at this point
  3242. return VCExpressionGenerator.EqOp;
  3243. case BinaryOperator.Opcode.Neq:
  3244. return VCExpressionGenerator.NeqOp;
  3245. case BinaryOperator.Opcode.Lt:
  3246. return VCExpressionGenerator.LtOp;
  3247. case BinaryOperator.Opcode.Le:
  3248. return VCExpressionGenerator.LeOp;
  3249. case BinaryOperator.Opcode.Ge:
  3250. return VCExpressionGenerator.GeOp;
  3251. case BinaryOperator.Opcode.Gt:
  3252. return VCExpressionGenerator.GtOp;
  3253. case BinaryOperator.Opcode.Imp:
  3254. return VCExpressionGenerator.ImpliesOp;
  3255. case BinaryOperator.Opcode.And:
  3256. return VCExpressionGenerator.AndOp;
  3257. case BinaryOperator.Opcode.Or:
  3258. return VCExpressionGenerator.OrOp;
  3259. case BinaryOperator.Opcode.Subtype:
  3260. return VCExpressionGenerator.SubtypeOp;
  3261. default:
  3262. Contract.Assert(false);
  3263. throw new NotImplementedException();
  3264. }
  3265. }
  3266. // If "false" is a post-predicate, then remove its "pre" constraint from all others, whenever possible
  3267. public void Simplify()
  3268. {
  3269. // find "false"
  3270. var findex = PostPreds[procName].FindIndex(ne => (ne.expr is LiteralExpr) && (ne.expr as LiteralExpr).IsFalse);
  3271. if (findex < 0) return;
  3272. if (value[findex].isTrue)
  3273. {
  3274. // procedure doesn't return
  3275. for (int i = 0; i < value.Length; i++)
  3276. if (i != findex) value[i] = new PredicateAbsDisjunct(false, procName);
  3277. return;
  3278. }
  3279. if (value[findex].isFalse)
  3280. return;
  3281. for (int i = 0; i < value.Length; i++)
  3282. if (i != findex) value[i].Subtract(value[findex]);
  3283. }
  3284. public HashSet<string> GetPredicates(Program program, VCExpressionGenerator gen, ProverInterface prover)
  3285. {
  3286. var ret = new HashSet<string>();
  3287. if (isFalse) return ret;
  3288. Simplify();
  3289. // Find the free expressions
  3290. var proc = program.Procedures.FirstOrDefault(p => p.Name == procName);
  3291. Contract.Assert(proc != null);
  3292. Expr freeSummary = Expr.True;
  3293. foreach (var req in proc.Requires.OfType<Requires>().Where(req => req.Free))
  3294. {
  3295. freeSummary = Expr.And(freeSummary, MakeOld(req.Condition));
  3296. }
  3297. foreach (var ens in proc.Ensures.OfType<Ensures>().Where(ens => ens.Free))
  3298. {
  3299. freeSummary = Expr.And(freeSummary, ens.Condition);
  3300. }
  3301. for (int i = 0; i < PostPreds[procName].Count; i++)
  3302. {
  3303. if (value[i].isFalse) continue;
  3304. if (PostPreds[procName][i].expr is LiteralExpr && (PostPreds[procName][i].expr as LiteralExpr).IsFalse)
  3305. continue;
  3306. if (value[i].isTrue)
  3307. ret.Add(PostPreds[procName][i].expr.ToString());
  3308. else
  3309. {
  3310. foreach (var c in value[i].GetConjuncts())
  3311. {
  3312. var s = Expr.Imp(c.ToExpr(j => PrePreds[procName][j].expr), PostPreds[procName][i].expr);
  3313. if (CheckIfUnsat(Expr.And(freeSummary, Expr.Not(s)), gen, prover))
  3314. continue;
  3315. ret.Add(s.ToString());
  3316. }
  3317. }
  3318. }
  3319. return ret;
  3320. }
  3321. public override string ToString()
  3322. {
  3323. var ret = "";
  3324. if (isFalse) return "false";
  3325. var first = true;
  3326. for(int i = 0; i < PostPreds[procName].Count; i++)
  3327. {
  3328. if(value[i].isFalse) continue;
  3329. if(value[i].isTrue)
  3330. ret += string.Format("{0}{1}", first ? "" : " && ", PostPreds[procName][i]);
  3331. else
  3332. ret += string.Format("{0}({1} ==> {2})", first ? "" : " && ", value[i], PostPreds[procName][i]);
  3333. first = false;
  3334. }
  3335. if (ret == "") ret = "true";
  3336. return ret;
  3337. }
  3338. #region ISummaryElement Members
  3339. public ISummaryElement Copy()
  3340. {
  3341. var ret = new PredicateAbs(procName);
  3342. ret.isFalse = isFalse;
  3343. ret.value = new PredicateAbsDisjunct[value.Length];
  3344. for (int i = 0; i < value.Length; i++)
  3345. ret.value[i] = value[i];
  3346. return ret;
  3347. }
  3348. public ISummaryElement GetFlaseSummary(Program program, Implementation impl)
  3349. {
  3350. return new PredicateAbs(impl.Name);
  3351. }
  3352. public ISummaryElement GetTrueSummary(Program program, Implementation impl)
  3353. {
  3354. var ret = new PredicateAbs(impl.Name);
  3355. ret.isFalse = false;
  3356. for (int i = 0; i < PostPreds[this.procName].Count; i++) ret.value[i] = new PredicateAbsDisjunct(false, impl.Name);
  3357. return ret;
  3358. }
  3359. public void Join(Dictionary<string, Model.Element> state, Model model)
  3360. {
  3361. PredicateAbs.model = model;
  3362. // Evaluate each predicate on the state
  3363. var prePredsVal = new bool[PrePreds[procName].Count];
  3364. var postPredsVal = new bool[PostPreds[procName].Count];
  3365. var indexSeq = new List<int>();
  3366. for (int i = 0; i < PrePreds[procName].Count; i++) indexSeq.Add(i);
  3367. for (int i = 0; i < PrePreds[procName].Count; i++)
  3368. {
  3369. var v = ToValue(Eval(PrePreds[procName][i].expr, state));
  3370. Debug.Assert(v is bool);
  3371. prePredsVal[i] = (bool)v;
  3372. }
  3373. for (int i = 0; i < PostPreds[procName].Count; i++)
  3374. {
  3375. var v = ToValue(Eval(PostPreds[procName][i].expr, state));
  3376. Debug.Assert(v is bool);
  3377. postPredsVal[i] = (bool)v;
  3378. }
  3379. for (int i = 0; i < PostPreds[procName].Count; i++)
  3380. {
  3381. // No hope for this post pred?
  3382. if (!isFalse && value[i].isFalse) continue;
  3383. var newDisj = new PredicateAbsDisjunct(true, procName);
  3384. if (!postPredsVal[i])
  3385. {
  3386. newDisj = new PredicateAbsDisjunct(indexSeq.Where(j => !prePredsVal[j]), indexSeq.Where(j => prePredsVal[j] && !PosPrePreds[procName].Contains(j)), procName);
  3387. }
  3388. if (isFalse)
  3389. value[i] = newDisj;
  3390. else
  3391. value[i] = PredicateAbsDisjunct.And(value[i], newDisj);
  3392. }
  3393. /*
  3394. // do beta(model)
  3395. var that = new PredicateAbsDisjunct[PostPreds[procName].Count];
  3396. for (int i = 0; i < PostPreds[procName].Count; i++)
  3397. {
  3398. if (postPredsVal[i])
  3399. that[i] = new PredicateAbsDisjunct(true, procName);
  3400. else if (i == 0)
  3401. {
  3402. Debug.Assert(PostPreds[procName][0].ToString() == "false");
  3403. var newDisj = new PredicateAbsDisjunct(true, procName);
  3404. newDisj = new PredicateAbsDisjunct(indexSeq.Where(j => !prePredsVal[j]), indexSeq.Where(j => prePredsVal[j]), procName);
  3405. that[i] = newDisj;
  3406. }
  3407. else
  3408. {
  3409. // false
  3410. that[i] = new PredicateAbsDisjunct(false, procName);
  3411. }
  3412. }
  3413. // Do join
  3414. for (int i = 0; i < PostPreds[procName].Count; i++)
  3415. {
  3416. if (isFalse)
  3417. value[i] = that[i];
  3418. else
  3419. {
  3420. if (i == 0)
  3421. value[i] = PredicateAbsDisjunct.And(value[i], that[i]);
  3422. else
  3423. {
  3424. var c1 = PredicateAbsDisjunct.And(value[i], that[i]);
  3425. var c2 = PredicateAbsDisjunct.And(value[i], that[0]);
  3426. var c3 = PredicateAbsDisjunct.And(value[0], that[i]);
  3427. value[i] = PredicateAbsDisjunct.Or(c1, c2);
  3428. value[i] = PredicateAbsDisjunct.Or(value[i], c3);
  3429. }
  3430. }
  3431. }
  3432. */
  3433. isFalse = false;
  3434. //Console.WriteLine("Result of Join: {0}", this.ToString());
  3435. }
  3436. // Precondition: the upper guys are just {true/false/upper-candidate} ==> post-pred
  3437. public void Meet(ISummaryElement iother)
  3438. {
  3439. var other = iother as PredicateAbs;
  3440. if (isFalse) return;
  3441. if (other.isFalse)
  3442. {
  3443. isFalse = true;
  3444. for (int i = 0; i < PostPreds[this.procName].Count; i++) value[i] = null;
  3445. return;
  3446. }
  3447. Debug.Assert(this.procName == other.procName);
  3448. for (int i = 0; i < PostPreds[this.procName].Count; i++)
  3449. {
  3450. value[i] = PredicateAbsDisjunct.Or(value[i], other.value[i]);
  3451. }
  3452. }
  3453. public bool IsEqual(ISummaryElement other)
  3454. {
  3455. var that = other as PredicateAbs;
  3456. if (isFalse && that.isFalse) return true;
  3457. if (isFalse || that.isFalse) return false;
  3458. for (int i = 0; i < PostPreds[procName].Count; i++)
  3459. {
  3460. if (!PredicateAbsDisjunct.syntacticLessThan(value[i], that.value[i]) ||
  3461. !PredicateAbsDisjunct.syntacticLessThan(that.value[i], value[i]))
  3462. return false;
  3463. }
  3464. return true;
  3465. }
  3466. // Precondition: the upper guys are just {true/false/upper-candidate} ==> post-pred
  3467. // Postcondition: the returned value is also of this form (for just one post-pred)
  3468. public ISummaryElement AbstractConsequence(ISummaryElement iupper)
  3469. {
  3470. var upper = iupper as PredicateAbs;
  3471. for (int i = 0; i < PostPreds[this.procName].Count; i++)
  3472. {
  3473. if (upper.value[i].isTrue) continue;
  3474. if (!UpperCandidates.ContainsKey(Tuple.Create(procName, i))) continue;
  3475. foreach (var candidate in UpperCandidates[Tuple.Create(procName, i)])
  3476. {
  3477. if (PredicateAbsDisjunct.syntacticLessThan(candidate, upper.value[i]))
  3478. continue;
  3479. if (!this.isFalse && !PredicateAbsDisjunct.syntacticLessThan(candidate, this.value[i]))
  3480. continue;
  3481. var ret = new PredicateAbs(this.procName);
  3482. ret.isFalse = false;
  3483. for (int j = 0; j < PostPreds[this.procName].Count; j++)
  3484. ret.value[j] = new PredicateAbsDisjunct(false, this.procName);
  3485. ret.value[i] = candidate;
  3486. return ret;
  3487. }
  3488. }
  3489. // Giveup: the abstract consequence is too difficult to compute
  3490. return null;
  3491. }
  3492. public VCExpr GetSummaryExpr(Dictionary<string, VCExpr> incarnations, VCExpressionGenerator gen)
  3493. {
  3494. if (isFalse)
  3495. return VCExpressionGenerator.False;
  3496. var ret = VCExpressionGenerator.True;
  3497. for(int i = 0; i < PostPreds[procName].Count; i++)
  3498. {
  3499. ret = gen.AndSimp(ret, gen.ImpliesSimp(value[i].ToVcExpr(j => ToVcExpr(PrePreds[procName][j].expr, incarnations, gen), gen), ToVcExpr(PostPreds[procName][i].expr, incarnations, gen)));
  3500. }
  3501. return ret;
  3502. }
  3503. public Expr GetSummaryExpr(Func<string, Expr> always, Func<string, Expr> forold)
  3504. {
  3505. if (isFalse)
  3506. return Expr.False;
  3507. Expr ret = Expr.True;
  3508. for (int i = 0; i < PostPreds[procName].Count; i++)
  3509. {
  3510. ret = Expr.And(ret, Expr.Imp(value[i].ToExpr(j => ToExpr(PrePreds[procName][j].expr, always, forold)), ToExpr(PostPreds[procName][i].expr, always, forold)));
  3511. }
  3512. return ret;
  3513. }
  3514. #endregion
  3515. }
  3516. public class PredicateAbsDisjunct
  3517. {
  3518. List<PredicateAbsConjunct> conjuncts;
  3519. string ProcName;
  3520. public bool isTrue {get; private set;}
  3521. public bool isFalse
  3522. {
  3523. get
  3524. {
  3525. if (isTrue) return false;
  3526. return conjuncts.Count == 0;
  3527. }
  3528. }
  3529. public PredicateAbsDisjunct(bool isTrue, string ProcName)
  3530. {
  3531. this.isTrue = isTrue;
  3532. this.ProcName = ProcName;
  3533. conjuncts = new List<PredicateAbsConjunct>();
  3534. }
  3535. public PredicateAbsDisjunct(List<PredicateAbsConjunct> conjuncts, string ProcName)
  3536. {
  3537. isTrue = false;
  3538. this.conjuncts = conjuncts;
  3539. this.ProcName = ProcName;
  3540. }
  3541. // Disjunct of singleton conjuncts
  3542. public PredicateAbsDisjunct(IEnumerable<int> pos, IEnumerable<int> neg, string ProcName)
  3543. {
  3544. this.ProcName = ProcName;
  3545. conjuncts = new List<PredicateAbsConjunct>();
  3546. isTrue = false;
  3547. pos.Iter(p => conjuncts.Add(PredicateAbsConjunct.Singleton(p, true, ProcName)));
  3548. neg.Iter(p => conjuncts.Add(PredicateAbsConjunct.Singleton(p, false, ProcName)));
  3549. }
  3550. // Does d1 describe a smaller set of states than d2? This is true when every conjunct of d1
  3551. // is smaller than some conjunct of d2
  3552. public static bool syntacticLessThan(PredicateAbsDisjunct d1, PredicateAbsDisjunct d2)
  3553. {
  3554. if (d2.isTrue) return true;
  3555. if (d1.isTrue) return false;
  3556. if (d1.isFalse) return true;
  3557. if (d2.isFalse) return false;
  3558. foreach (var c1 in d1.conjuncts)
  3559. {
  3560. if (d2.conjuncts.Any(c2 => PredicateAbsConjunct.syntacticLessThan(c1, c2)))
  3561. continue;
  3562. else
  3563. return false;
  3564. }
  3565. return true;
  3566. }
  3567. public static PredicateAbsDisjunct And(PredicateAbsDisjunct v1, PredicateAbsDisjunct v2)
  3568. {
  3569. if (v1.isTrue) return v2;
  3570. if (v2.isTrue) return v1;
  3571. var result = new List<PredicateAbsConjunct>();
  3572. foreach (var c1 in v1.conjuncts)
  3573. {
  3574. foreach (var c2 in v2.conjuncts)
  3575. {
  3576. var c = PredicateAbsConjunct.And(c1, c2);
  3577. if (c.isFalse) continue;
  3578. if (result.Any(cprime => c.implies(cprime))) continue;
  3579. var tmp = new List<PredicateAbsConjunct>();
  3580. tmp.Add(c);
  3581. result.Where(cprime => !cprime.implies(c)).Iter(cprime => tmp.Add(cprime));
  3582. result = tmp;
  3583. }
  3584. }
  3585. return new PredicateAbsDisjunct(result, v1.ProcName);
  3586. }
  3587. public static PredicateAbsDisjunct Or(PredicateAbsDisjunct v1, PredicateAbsDisjunct v2)
  3588. {
  3589. if (v1.isTrue) return v1;
  3590. if (v2.isTrue) return v2;
  3591. if (v1.isFalse) return v2;
  3592. if (v2.isFalse) return v1;
  3593. var result = new List<PredicateAbsConjunct>();
  3594. v1.conjuncts.Iter(c => result.Add(c));
  3595. foreach (var c in v2.conjuncts)
  3596. {
  3597. if (result.Any(cprime => c.implies(cprime))) continue;
  3598. var tmp = new List<PredicateAbsConjunct>();
  3599. tmp.Add(c);
  3600. result.Where(cprime => !cprime.implies(c)).Iter(cprime => tmp.Add(cprime));
  3601. result = tmp;
  3602. }
  3603. return new PredicateAbsDisjunct(result, v1.ProcName);
  3604. }
  3605. public VCExpr ToVcExpr(Func<int, VCExpr> predToExpr, VCExpressionGenerator gen)
  3606. {
  3607. if (isTrue) return VCExpressionGenerator.True;
  3608. var ret = VCExpressionGenerator.False;
  3609. conjuncts.Iter(c => ret = gen.OrSimp(ret, c.ToVcExpr(predToExpr, gen)));
  3610. return ret;
  3611. }
  3612. public Expr ToExpr(Func<int, Expr> predToExpr)
  3613. {
  3614. if (isTrue) return Expr.True;
  3615. Expr ret = Expr.False;
  3616. conjuncts.Iter(c => ret = Expr.Or(ret, c.ToExpr(predToExpr)));
  3617. return ret;
  3618. }
  3619. public override string ToString()
  3620. {
  3621. if(isTrue)
  3622. return "true";
  3623. var ret = "";
  3624. var first = true;
  3625. foreach (var c in conjuncts)
  3626. {
  3627. if (c.isFalse) continue;
  3628. ret += string.Format("{0}{1}", first ? "" : " || ", c);
  3629. first = false;
  3630. }
  3631. return ret;
  3632. }
  3633. public void Subtract(PredicateAbsDisjunct that)
  3634. {
  3635. var ncon = new List<PredicateAbsConjunct>();
  3636. foreach (var c1 in conjuncts)
  3637. {
  3638. if (that.conjuncts.Any(c2 => c1.implies(c2)))
  3639. continue;
  3640. ncon.Add(c1);
  3641. }
  3642. conjuncts = ncon;
  3643. }
  3644. public IEnumerable<PredicateAbsConjunct> GetConjuncts()
  3645. {
  3646. return conjuncts;
  3647. }
  3648. }
  3649. public class PredicateAbsConjunct
  3650. {
  3651. static int ConjunctBound = 3;
  3652. public bool isFalse { get; private set; }
  3653. HashSet<int> posPreds;
  3654. HashSet<int> negPreds;
  3655. string ProcName;
  3656. public static void Initialize(int bound)
  3657. {
  3658. ConjunctBound = bound;
  3659. }
  3660. private void Normalize()
  3661. {
  3662. if (posPreds.Intersect(negPreds).Any() || negPreds.Intersect(posPreds).Any() || (posPreds.Count + negPreds.Count > ConjunctBound))
  3663. {
  3664. isFalse = true;
  3665. posPreds = new HashSet<int>();
  3666. negPreds = new HashSet<int>();
  3667. }
  3668. }
  3669. // Do this step only once in a while?
  3670. private void StrongNormalize()
  3671. {
  3672. if (isFalse) return;
  3673. var candidates = new List<Tuple<int, bool>>();
  3674. posPreds.Iter(p => candidates.Add(Tuple.Create(p, true)));
  3675. negPreds.Iter(p => candidates.Add(Tuple.Create(p, false)));
  3676. var drop = new HashSet<int>();
  3677. for (int i = 0; i < candidates.Count; i++)
  3678. {
  3679. for (int j = 0; j < candidates.Count; j++)
  3680. {
  3681. if (i == j) continue;
  3682. var key = Tuple.Create(ProcName, candidates[i].Item1, candidates[j].Item1,
  3683. candidates[i].Item2, candidates[j].Item2);
  3684. if (PredicateAbs.unsatPrePredPairs.Contains(key))
  3685. {
  3686. isFalse = true;
  3687. posPreds = new HashSet<int>();
  3688. negPreds = new HashSet<int>();
  3689. return;
  3690. }
  3691. key = Tuple.Create(ProcName, candidates[i].Item1, candidates[j].Item1,
  3692. candidates[i].Item2, !candidates[j].Item2);
  3693. if (PredicateAbs.unsatPrePredPairs.Contains(key))
  3694. drop.Add(candidates[j].Item1);
  3695. }
  3696. }
  3697. posPreds.ExceptWith(drop);
  3698. negPreds.ExceptWith(drop);
  3699. }
  3700. public PredicateAbsConjunct(bool isFalse, string ProcName)
  3701. {
  3702. posPreds = new HashSet<int>();
  3703. negPreds = new HashSet<int>();
  3704. this.isFalse = isFalse;
  3705. this.ProcName = ProcName;
  3706. }
  3707. // do we know that c1 is surely less than or equal to c2? That is, c1 describes a smaller
  3708. // concretization. We check that c2 is a sub-conjunct of c1
  3709. public static bool syntacticLessThan(PredicateAbsConjunct c1, PredicateAbsConjunct c2)
  3710. {
  3711. if (c1.isFalse) return true;
  3712. if (c2.isFalse) return false;
  3713. return (c2.posPreds.IsSubsetOf(c1.posPreds) && c2.negPreds.IsSubsetOf(c1.negPreds));
  3714. }
  3715. public static PredicateAbsConjunct Singleton(int v, bool isPositive, string ProcName)
  3716. {
  3717. if (isPositive)
  3718. return new PredicateAbsConjunct(new int[] { v }, new HashSet<int>(), ProcName);
  3719. else
  3720. return new PredicateAbsConjunct(new HashSet<int>(), new int[] { v }, ProcName);
  3721. }
  3722. public PredicateAbsConjunct(IEnumerable<int> pos, IEnumerable<int> neg, string ProcName)
  3723. {
  3724. isFalse = false;
  3725. posPreds = new HashSet<int>(pos);
  3726. negPreds = new HashSet<int>(neg);
  3727. this.ProcName = ProcName;
  3728. Normalize();
  3729. }
  3730. public static PredicateAbsConjunct And(PredicateAbsConjunct v1, PredicateAbsConjunct v2)
  3731. {
  3732. if (v1.isFalse || v2.isFalse) return new PredicateAbsConjunct(true, v1.ProcName);
  3733. var ret = new PredicateAbsConjunct(v1.posPreds.Union(v2.posPreds), v1.negPreds.Union(v2.negPreds), v1.ProcName);
  3734. ret.StrongNormalize();
  3735. return ret;
  3736. }
  3737. public bool implies(PredicateAbsConjunct v)
  3738. {
  3739. if (isFalse) return true;
  3740. if (v.isFalse) return false;
  3741. return (posPreds.IsSupersetOf(v.posPreds) && negPreds.IsSupersetOf(v.negPreds));
  3742. }
  3743. public VCExpr ToVcExpr(Func<int, VCExpr> predToExpr, VCExpressionGenerator gen)
  3744. {
  3745. if (isFalse) return VCExpressionGenerator.False;
  3746. var ret = VCExpressionGenerator.True;
  3747. posPreds.Iter(p => ret = gen.AndSimp(ret, predToExpr(p)));
  3748. negPreds.Iter(p => ret = gen.AndSimp(ret, gen.Not(predToExpr(p))));
  3749. return ret;
  3750. }
  3751. public Expr ToExpr(Func<int, Expr> predToExpr)
  3752. {
  3753. if (isFalse) return Expr.False;
  3754. Expr ret = Expr.True;
  3755. var pp = posPreds.ToList(); pp.Sort();
  3756. var np = negPreds.ToList(); np.Sort();
  3757. pp.Iter(p => ret = Expr.And(ret, predToExpr(p)));
  3758. np.Iter(p => ret = Expr.And(ret, Expr.Not(predToExpr(p))));
  3759. return ret;
  3760. }
  3761. public override string ToString()
  3762. {
  3763. if (isFalse)
  3764. return "false";
  3765. var ret = "";
  3766. var first = true;
  3767. foreach (var p in posPreds)
  3768. {
  3769. ret += string.Format("{0}{1}", first ? "" : " && ", PredicateAbs.PrePreds[ProcName][p]);
  3770. first = false;
  3771. }
  3772. foreach (var p in negPreds)
  3773. {
  3774. ret += string.Format("{0}!{1}", first ? "" : " && ", PredicateAbs.PrePreds[ProcName][p]);
  3775. first = false;
  3776. }
  3777. return ret;
  3778. }
  3779. }
  3780. class FindSummaryPred : MutatingVCExprVisitor<bool>
  3781. {
  3782. public List<Tuple<string, bool, VCExprVar, VCExprNAry>> summaryPreds;
  3783. int assertId;
  3784. private static int CounterId = 0;
  3785. public FindSummaryPred(VCExpressionGenerator gen, int assertId)
  3786. : base(gen)
  3787. {
  3788. summaryPreds = new List<Tuple<string, bool, VCExprVar, VCExprNAry>>();
  3789. this.assertId = assertId;
  3790. }
  3791. protected override VCExpr/*!*/ UpdateModifiedNode(VCExprNAry/*!*/ originalNode,
  3792. List<VCExpr/*!*/>/*!*/ newSubExprs,
  3793. // has any of the subexpressions changed?
  3794. bool changed,
  3795. bool arg)
  3796. {
  3797. Contract.Ensures(Contract.Result<VCExpr>() != null);
  3798. VCExpr ret;
  3799. if (changed)
  3800. ret = Gen.Function(originalNode.Op,
  3801. newSubExprs, originalNode.TypeArguments);
  3802. else
  3803. ret = originalNode;
  3804. VCExprNAry retnary = ret as VCExprNAry;
  3805. if (retnary == null) return ret;
  3806. var op = retnary.Op as VCExprBoogieFunctionOp;
  3807. if (op == null)
  3808. {
  3809. var lop = retnary.Op as VCExprLabelOp;
  3810. if (lop == null) return ret;
  3811. if (lop.pos) return ret;
  3812. if (!lop.label.Equals("@" + assertId.ToString())) return ret;
  3813. //var subexpr = retnary[0] as VCExprNAry;
  3814. //if (subexpr == null) return ret;
  3815. //op = subexpr.Op as VCExprBoogieFunctionOp;
  3816. //if (op == null) return ret;
  3817. var subexpr = retnary[0] as VCExprVar;
  3818. if (subexpr == null) return ret;
  3819. if (!subexpr.Name.StartsWith("AbstractHoudiniControl")) return ret;
  3820. for (int i = 0; i < summaryPreds.Count; i++)
  3821. {
  3822. if (summaryPreds[i].Item3 == subexpr)
  3823. summaryPreds[i] = Tuple.Create(summaryPreds[i].Item1, true, summaryPreds[i].Item3, summaryPreds[i].Item4);
  3824. }
  3825. return ret;
  3826. }
  3827. string calleeName = op.Func.Name;
  3828. if (!calleeName.EndsWith(AbstractHoudini.summaryPredSuffix))
  3829. return ret;
  3830. var controlConst = Gen.Variable("AbstractHoudiniControl" + CounterId, Microsoft.Boogie.Type.Bool);
  3831. CounterId++;
  3832. summaryPreds.Add(Tuple.Create(calleeName.Substring(0, calleeName.Length - AbstractHoudini.summaryPredSuffix.Length), false, controlConst, retnary));
  3833. return controlConst;
  3834. //return ret;
  3835. }
  3836. }
  3837. class FindExistentialFunctions : MutatingVCExprVisitor<bool>
  3838. {
  3839. public List<Tuple<string, VCExprVar, VCExprNAry>> funcCalls;
  3840. private HashSet<string> existentialFunctions;
  3841. private static int CounterId = 0;
  3842. public FindExistentialFunctions(VCExpressionGenerator gen, HashSet<string> existentialFunctions)
  3843. : base(gen)
  3844. {
  3845. funcCalls = new List<Tuple<string, VCExprVar, VCExprNAry>>();
  3846. this.existentialFunctions = existentialFunctions;
  3847. }
  3848. protected override VCExpr/*!*/ UpdateModifiedNode(VCExprNAry/*!*/ originalNode,
  3849. List<VCExpr/*!*/>/*!*/ newSubExprs,
  3850. // has any of the subexpressions changed?
  3851. bool changed,
  3852. bool arg)
  3853. {
  3854. Contract.Ensures(Contract.Result<VCExpr>() != null);
  3855. VCExpr ret;
  3856. if (changed)
  3857. ret = Gen.Function(originalNode.Op,
  3858. newSubExprs, originalNode.TypeArguments);
  3859. else
  3860. ret = originalNode;
  3861. VCExprNAry retnary = ret as VCExprNAry;
  3862. if (retnary == null) return ret;
  3863. var op = retnary.Op as VCExprBoogieFunctionOp;
  3864. if (op == null) return ret;
  3865. string calleeName = op.Func.Name;
  3866. if (!existentialFunctions.Contains(calleeName))
  3867. return ret;
  3868. var controlConst = Gen.Variable("AbsHoudiniControl" + CounterId, Microsoft.Boogie.Type.Bool);
  3869. CounterId++;
  3870. funcCalls.Add(Tuple.Create(calleeName, controlConst, retnary));
  3871. return controlConst;
  3872. }
  3873. }
  3874. class AbstractHoudiniErrorReporter : ProverInterface.ErrorHandler
  3875. {
  3876. public Model model;
  3877. public AbstractHoudiniErrorReporter()
  3878. {
  3879. model = null;
  3880. }
  3881. public override void OnModel(IList<string> labels, Model model, ProverInterface.Outcome proverOutcome)
  3882. {
  3883. Debug.Assert(model != null);
  3884. if(CommandLineOptions.Clo.PrintErrorModel >= 1) model.Write(Console.Out);
  3885. this.model = model;
  3886. }
  3887. }
  3888. public class AbsHoudiniInternalError : System.ApplicationException
  3889. {
  3890. public AbsHoudiniInternalError(string msg) : base(msg) { }
  3891. };
  3892. public class SimpleUtil
  3893. {
  3894. // Constructs a mapping from procedure names to the implementation
  3895. public static Dictionary<string, Implementation> nameImplMapping(Program p)
  3896. {
  3897. var m = new Dictionary<string, Implementation>();
  3898. foreach (var impl in p.Implementations)
  3899. {
  3900. m.Add(impl.Name, impl);
  3901. }
  3902. return m;
  3903. }
  3904. // is "assert true"?
  3905. public static bool isAssertTrue(Cmd cmd)
  3906. {
  3907. var acmd = cmd as AssertCmd;
  3908. if (acmd == null) return false;
  3909. var le = acmd.Expr as LiteralExpr;
  3910. if (le == null) return false;
  3911. if (le.IsTrue) return true;
  3912. return false;
  3913. }
  3914. }
  3915. }