PageRenderTime 72ms CodeModel.GetById 27ms RepoModel.GetById 1ms app.codeStats 1ms

/Source/Houdini/AbstractHoudini.cs

#
C# | 4609 lines | 3666 code | 693 blank | 250 comment | 715 complexity | e5add6417232b0ae9b3a8eaaf32279ed MD5 | raw file

Large files files are truncated, but you can click here to view the full 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";

Large files files are truncated, but you can click here to view the full file