//return first reachable blocks from block in afterPassificationCfg, which are non-empty and contained in finalCfg private static IEnumerable <Block> GetNonEmptyReachableSuccessors( Block afterPassiveBlock, CFGRepr afterPassificationCfg, CFGRepr finalCfg, IDictionary <Block, Block> afterPassiveToFinalBlock) { //block is unreachable after peephole var nonEmptySuccessors = new HashSet <Block>(); if (afterPassificationCfg.NumOfSuccessors(afterPassiveBlock) > 0) { //find first reachable blocks that are not empty var toVisit = new Queue <Block>(); toVisit.Enqueue(afterPassiveBlock); while (toVisit.Count > 0) { var curBlock = toVisit.Dequeue(); if (curBlock.Cmds.Count != 0 && finalCfg.ContainsBlock(afterPassiveToFinalBlock[curBlock])) { nonEmptySuccessors.Add(curBlock); } else { foreach (var succ in afterPassificationCfg.GetSuccessorBlocks(curBlock)) { toVisit.Enqueue(succ); } } } } return(nonEmptySuccessors); }
/// <summary> /// Provide source CFG for passification phase /// </summary> public static void BeforePassification(Implementation impl) { if (CommandLineOptions.Clo.GenerateIsaProgNoProofs) { return; } var config = new CFGReprConfigBuilder().SetIsAcyclic(true).SetBlockCopy(true).SetDesugarCalls(true) .Build(); beforePassificationCfg = CFGReprTransformer.GetCfgRepresentation( impl, config, out beforePassiveOrigBlock, out var newVarsFromDesugaring ); cfgToDagHintManager.AfterDagToOrig = beforePassiveOrigBlock; beforePassiveData = MethodDataFromImpl(impl, boogieGlobalData, newVarsFromDesugaring); passificationHintManager = new PassificationHintManager(beforePassiveOrigBlock); initialVarMapping = new Dictionary <Block, IDictionary <Variable, Expr> >(); // compute mapping between copied blocks (before dag -> after dag) var origToAfterDag = beforePassiveOrigBlock.InverseDict(); beforeDagAfterDagBlock = DictionaryComposition(beforeDagOrigBlock, origToAfterDag); }
public PassificationLemmaManager( CFGRepr cfg, IDictionary <Block, Block> origToPassiveBlock, IProgramAccessor programAccessor, IProgramAccessor passiveProgramAccessor, Tuple <string, string> varContextNonPassivePassive, StateRelationData oldStateRelationData, PassiveRelationGen relationGen, IVariableTranslationFactory varTranslationFactory, IVariableTranslationFactory passiveTranslationFactory) { this.cfg = cfg; this.origToPassiveBlock = origToPassiveBlock; this.programAccessor = programAccessor; this.passiveProgramAccessor = passiveProgramAccessor; _oldStateRelationData = oldStateRelationData; _relationGen = relationGen; initState = IsaBoogieTerm.Normal(normalInitState); varTranslation = varTranslationFactory.CreateTranslation().VarTranslation; passiveVarTranslation = passiveTranslationFactory.CreateTranslation().VarTranslation; //separate unique namer for function interpretations (since they already have a name in uniqueNamer): possible clashes boogieContext = new BoogieContextIsa( IsaCommonTerms.TermIdentFromName("A"), IsaCommonTerms.TermIdentFromName("M"), IsaCommonTerms.TermIdentFromName(varContextNonPassivePassive.Item1), IsaCommonTerms.TermIdentFromName("\\<Gamma>"), IsaCommonTerms.TermIdentFromName("\\<Omega>") ); passiveVarContext = IsaCommonTerms.TermIdentFromName(varContextNonPassivePassive.Item2); }
public static bool CheckVersionMap( IDictionary <Variable, int> versionMap, PassiveRelationGen relationGen, CFGRepr beforePassiveBlocks, IDictionary <Block, Block> beforeToPassiveBlocks ) { return(GlobalVersion.CheckIsGlobal(beforeToPassiveBlocks.Values.ToList(), relationGen, versionMap, relationGen.LiveVarsBeforeBlock(beforePassiveBlocks.entry))); }
/// <summary> /// Provide source CFG for CFG-to-DAG phase /// </summary> public static void BeforeCFGToDAG(Implementation impl) { var config = new CFGReprConfigBuilder().SetIsAcyclic(false).SetBlockCopy(true).SetDesugarCalls(true) .Build(); beforeDagCfg = CFGReprTransformer.GetCfgRepresentation(impl, config, out beforeDagOrigBlock, out var newVarsFromDesugaring); beforeDagData = MethodDataFromImpl(impl, boogieGlobalData, newVarsFromDesugaring); uniqueExitBlockOrig = null; }
/// <summary> /// Provide target CFG for passification phase, construct global version map. /// </summary> /// <param name="impl">source CFG after passification phase</param> /// <exception cref="ProofGenUnexpectedStateException">thrown if global version map is incorrect /// (should never happen). </exception> public static void AfterPassificationCheckGlobalMap(Implementation impl) { afterPassificationImpl = impl; if (CommandLineOptions.Clo.GenerateIsaProgNoProofs) { return; } finalProgData = MethodDataFromImpl(impl, boogieGlobalData); var config = new CFGReprConfigBuilder().SetIsAcyclic(true).SetBlockCopy(true).SetDesugarCalls(false) .SetDeepCopyPredCmd(TypeCheckBeforeVcMaybeRewritesCmd).Build(); afterPassificationCfg = CFGReprTransformer.GetCfgRepresentation(impl, config, out afterPassificationToOrigBlock, out _); var passiveBlocks = new List <Block>(afterPassificationCfg.GetBlocksBackwards()); var origToAfterPassificationBlock = afterPassificationToOrigBlock.InverseDict(); beforePassiveToAfterPassiveBlock = DictionaryComposition(beforePassiveOrigBlock, origToAfterPassificationBlock); var globalVersion = new GlobalVersion(); passiveRelationGen = new PassiveRelationGen( beforePassificationCfg, passificationHintManager, initialVarMapping, beforePassiveOrigBlock, beforePassiveToAfterPassiveBlock, ProofGenLiveVarAnalysis.ComputeLiveVariables(beforePassificationCfg, beforePassiveData) ); //all variables before passification are the initial versions and already constrained globalVersionMap = globalVersion.GlobalVersionMap( passiveRelationGen, beforePassiveData.AllVariables(), afterPassificationCfg.entry, passiveBlocks); //Console.WriteLine("Version map: " + string.Join(Environment.NewLine, globalVersionMap)); var versionMapCorrect = GlobalVersionChecker.CheckVersionMap(globalVersionMap, passiveRelationGen, beforePassificationCfg, beforePassiveToAfterPassiveBlock); if (!versionMapCorrect) { throw new ProofGenUnexpectedStateException(typeof(ProofGenerationLayer), "Incorrect version map"); } }
private static IDictionary <Block, OuterDecl> GenerateCfgLemmas( CFGRepr afterPassificationCfg, CFGRepr finalCfg, IDictionary <Block, Block> afterPassiveToFinalBlock, HashSet <Block> reachableBlocks, IDictionary <Block, IList <OuterDecl> > lemmaDecls, VcPhaseLemmaManager vcPhaseLemmaManager, Term cfgTerm, IsaUniqueNamer lemmaNamer) { var blockToLemmaDecls = new Dictionary <Block, OuterDecl>(); foreach (var bAfterPassive in afterPassificationCfg.GetBlocksBackwards()) { IEnumerable <Block> finalCfgSuccessors; var isContainedInFinalCfg = afterPassiveToFinalBlock.TryGetValue(bAfterPassive, out var bFinal); if (!isContainedInFinalCfg) { if (reachableBlocks.Contains(bAfterPassive)) { finalCfgSuccessors = GetNonEmptyReachableSuccessors(bAfterPassive, afterPassificationCfg, finalCfg, afterPassiveToFinalBlock).Select(b => afterPassiveToFinalBlock[b]); } else { continue; } } else { finalCfgSuccessors = finalCfg.GetSuccessorBlocks(bFinal); } var lemma = vcPhaseLemmaManager.GenerateCfgLemma( bAfterPassive, bFinal, isContainedInFinalCfg, afterPassificationCfg.GetSuccessorBlocks(bAfterPassive), finalCfgSuccessors, cfgTerm, b => "cfg_" + lemmaNamer.GetName(b, b.Label), (LemmaDecl)lemmaDecls[bAfterPassive].Last()); blockToLemmaDecls.Add(bAfterPassive, lemma); } return(blockToLemmaDecls); }
public PassiveRelationGen( CFGRepr beforePassiveCfg, PassificationHintManager hintManager, IDictionary <Block, IDictionary <Variable, Expr> > origToInitialVarMapping, IDictionary <Block, Block> nonPassiveToOrig, IDictionary <Block, Block> nonPassiveToPassive, IDictionary <Block, IEnumerable <Variable> > liveVarsBefore) { this.beforePassiveCfg = beforePassiveCfg; this.hintManager = hintManager; _origToInitialVarMapping = origToInitialVarMapping; this.nonPassiveToOrig = nonPassiveToOrig; this.nonPassiveToPassive = nonPassiveToPassive; passiveToNonPassive = nonPassiveToPassive.InverseDict(); this.liveVarsBefore = liveVarsBefore; }
private ContextElem LemmaContext( CFGRepr cfg, Term vcAssm ) { var multiRed = IsaBoogieTerm.RedCFGMulti( BoogieContextIsa.CreateWithNewVarContext( boogieContext, new TermTuple(programAccessor.ConstsAndGlobalsDecl(), programAccessor.ParamsAndLocalsDecl()) ), programAccessor.CfgDecl(), IsaBoogieTerm.CFGConfigNode(new NatConst(cfg.GetUniqueIntLabel(cfg.entry)), IsaBoogieTerm.Normal(normalInitState)), IsaBoogieTerm.CFGConfig(finalNodeOrReturn, finalState) ); var closedAssm = EndToEndAssumptions.ClosednessAssumption(boogieContext.absValTyMap); var nonEmptyTypesAssm = EndToEndAssumptions.NonEmptyTypesAssumption(boogieContext.absValTyMap); var finterpAssm = IsaBoogieTerm.FunInterpWf(boogieContext.absValTyMap, programAccessor.FunctionsDecl(), boogieContext.funContext); var absValType = new VarType("a"); //need to explicitly give type for normal state, otherwise Isabelle won't know that the abstract value type is the same as used in the VC var axiomAssm = EndToEndAssumptions.AxiomAssumption(boogieContext, programAccessor, new TermWithExplicitType(normalInitState, IsaBoogieType.NormalStateType(absValType))); var presAssm = IsaBoogieTerm.ExprAllSat(boogieContext, normalInitState, programAccessor.PreconditionsDecl()); var localsAssm = EndToEndAssumptions.LocalStateAssumption(boogieContext, IsaCommonTerms.Snd(boogieContext.varContext), normalInitState); var globalsAssm = EndToEndAssumptions.GlobalStateAssumption(boogieContext, IsaCommonTerms.Fst(boogieContext.varContext), normalInitState); var oldGlobalStateAssm = EndToEndAssumptions.OldGlobalStateAssumption(normalInitState); var binderEmptyAssm = EndToEndAssumptions.BinderStateEmpty(normalInitState); return (ContextElem.CreateWithAssumptions( new List <Term> { multiRed, vcAssm, closedAssm, nonEmptyTypesAssm, finterpAssm, axiomAssm, presAssm, localsAssm, globalsAssm, oldGlobalStateAssm, binderEmptyAssm }, new List <string> { redAssmName, vcAssmName, closedAssmName, nonEmptyTypesAssmName, finterpAssmName, axiomAssmName, preconditionsAssmName, paramsLocalsAssmName, constsGlobalsAssmName, oldGlobalAssmName, binderEmptyAssmName } )); }
/// <summary> /// Provide target CFG after unreachable blocks are pruned (after passification). /// </summary> public static void AfterUnreachablePruning(Implementation impl) { if (CommandLineOptions.Clo.GenerateIsaProgNoProofs) { return; } var config = new CFGReprConfigBuilder().SetIsAcyclic(true).SetBlockCopy(true).SetDesugarCalls(false) .SetDeepCopyPredCmd(TypeCheckBeforeVcMaybeRewritesCmd).Build(); afterUnreachablePruningCfg = CFGReprTransformer.GetCfgRepresentation(impl, config, out var afterUnreachableToOrigBlock, out _); var origToAfterUnreachableBlock = afterUnreachableToOrigBlock.InverseDict(); afterPassificationToAfterUnreachableBlock = DictionaryComposition(afterPassificationToOrigBlock, origToAfterUnreachableBlock); }
public IEnumerable <OuterDecl> EndToEndProof( string entryCfgLemma, string boogieToVcLemma, Term vcAssm, IProgramAccessor programAccessor, IProgramAccessor passiveProgramAccessor, Tuple <string, string> varContextNonPassivePassive, StateRelationData oldRelationData, CFGRepr cfg, IEnumerable <Variable> liveEntryVars, IVariableTranslation <Variable> varTranslation) { this.entryCfgLemma = entryCfgLemma; this.boogieToVcLemma = boogieToVcLemma; this.vcAssm = vcAssm; this.programAccessor = programAccessor; this.passiveProgramAccessor = passiveProgramAccessor; boogieContext = new BoogieContextIsa( IsaCommonTerms.TermIdentFromName("A"), IsaCommonTerms.TermIdentFromName("M"), IsaCommonTerms.TermIdentFromName(varContextNonPassivePassive.Item1), IsaCommonTerms.TermIdentFromName("\\<Gamma>"), IsaCommonTerms.EmptyList ); passiveVarContext = IsaCommonTerms.TermIdentFromName(varContextNonPassivePassive.Item2); this.oldRelationData = oldRelationData; this.cfg = cfg; this.liveEntryVars = liveEntryVars; this.varTranslation = varTranslation; var locale = new LocaleDecl("glue_proof", Context(), GenerateLemma() ); return(new List <OuterDecl> { locale }); }
//if blockToNewVars is non-null, then the mapped variables are universally quantified for the corresponding block definition public IDictionary <Block, DefDecl> IsaDefsFromVC(IDictionary <Block, VCExpr> blockToVC, IDictionary <Block, IList <VCExprVar> > blockToActiveVars, CFGRepr cfg, IDictionary <Block, IList <VCExprVar> > blockToNewVars = null) { Contract.Ensures(Contract.Result <IDictionary <Block, DefDecl> >().Count == cfg.NumOfBlocks()); IDictionary <Block, DefDecl> blockToDefVC = new Dictionary <Block, DefDecl>(); var vcExprIsaVisitor = new VCExprToIsaTranslator(uniqueNamer, blockToDefVC, blockToActiveVars); foreach (var block in cfg.GetBlocksBackwards()) { // might be more efficient to hand over this: // IEnumerable<Tuple<Block, DefDecl>> successorDefs = cfg.outgoingBlocks[block].Select(b => new Tuple<Block, DefDecl>(b, blockToDefVC[b])); var term = vcExprIsaVisitor.Translate(blockToVC[block]); if (blockToNewVars != null && blockToNewVars.TryGetValue(block, out var newVars) && newVars != null && newVars.Any()) { IList <Identifier> boundVars = newVars .Select(v => (Identifier) new SimpleIdentifier(uniqueNamer.GetName(v, v.Name))).ToList(); IList <TypeIsa> boundVarsTypes = newVars.Select(v => pureTyIsaTransformer.Translate(v.Type)).ToList(); term = new TermQuantifier(TermQuantifier.QuantifierKind.ALL, boundVars, boundVarsTypes, term); } IList <Term> args = blockToActiveVars[block].Select(v => vcExprIsaVisitor.Translate(v)).ToList(); var def = new DefDecl(GetVCDefName(block), new Tuple <IList <Term>, Term>(args, term)); Contract.Assert(!blockToDefVC.ContainsKey(block)); blockToDefVC.Add(block, def); } return(blockToDefVC); }
private static HashSet <Block> ReachableBlocks(CFGRepr cfg) { var reachableBlocks = new HashSet <Block>(); var queue = new Queue <Block>(); reachableBlocks.Add(cfg.entry); queue.Enqueue(cfg.entry); while (queue.TryDequeue(out var b)) { if (!LemmaHelper.FinalStateIsMagic(b)) { //b's successors are not trivially unreachable var successors = cfg.GetSuccessorBlocks(b); foreach (var suc in successors) { reachableBlocks.Add(suc); queue.Enqueue(suc); } } } return(reachableBlocks); }
/// <summary> /// Returns a mapping from blocks to corresponding verification conditions /// Assumes that the expression defines a separate let binding for each block, where the name of the variable is given /// by /// "blockName_correct" /// </summary> public static IDictionary <Block, VCExpr> BlockToVCMapping(VCExprLet letExpr, CFGRepr cfg) { var blockToVC = new Dictionary <Block, VCExpr>(); foreach (var binding in letExpr) { var predictionSuccess = PredictBlockName(binding.V.Name, out var predictedBlockName); if (predictionSuccess) { try { var block = cfg.GetBlocksForwards().Single(b => b.Label.Equals(predictedBlockName)); blockToVC.Add(block, binding.E); } catch (Exception e) { throw new ProofGenUnexpectedStateException(typeof(VCBlockExtractor), e.Message); } } else { throw new ProofGenUnexpectedStateException(typeof(VCBlockExtractor), "let binding does not correspond to block"); } } if (blockToVC.Count != cfg.NumOfBlocks()) { throw new ProofGenUnexpectedStateException(typeof(VCBlockExtractor), "could not find let binding for all blocks"); } return(blockToVC); }
public IEnumerable <OuterDecl> EndToEndProof( string entryCfgLemma, string passificationEndToEndLemma, Term vcAssm, IProgramAccessor programAccessor, CFGRepr cfg) { this.programAccessor = programAccessor; boogieContext = new BoogieContextIsa( IsaCommonTerms.TermIdentFromName("A"), IsaCommonTerms.TermIdentFromName("M"), IsaCommonTerms.TermIdentFromName(varContextName), IsaCommonTerms.TermIdentFromName("\\<Gamma>"), IsaCommonTerms.EmptyList ); var abbrev = new AbbreviationDecl( varContextName, new Tuple <IList <Term>, Term>(new List <Term>(), new TermTuple(programAccessor.ConstsAndGlobalsDecl(), programAccessor.ParamsAndLocalsDecl())) ); var result = new List <OuterDecl> { abbrev }; var kStepRed = IsaBoogieTerm.RedCFGKStep( BoogieContextIsa.CreateWithNewVarContext( boogieContext, new TermTuple(programAccessor.ConstsAndGlobalsDecl(), programAccessor.ParamsAndLocalsDecl()) ), programAccessor.CfgDecl(), IsaBoogieTerm.CFGConfigNode(new NatConst(cfg.GetUniqueIntLabel(cfg.entry)), IsaBoogieTerm.Normal(normalInitState)), IsaCommonTerms.TermIdentFromName("j"), IsaBoogieTerm.CFGConfig(finalNodeOrReturn, finalState) ); var proofSb = new StringBuilder(); proofSb.AppendLine("proof -"); proofSb.AppendLine("from " + redAssmName + " obtain j where Aux:" + "\"" + kStepRed + "\""); proofSb.AppendLine("by (meson rtranclp_imp_relpowp)"); proofSb.AppendLine("show ?thesis"); proofSb.AppendLine(ProofUtil.Apply("rule " + entryCfgLemma)); //TODO: don't hardcode this proofSb.AppendLine("unfolding cfg_to_dag_lemmas_def"); proofSb.AppendLine(ProofUtil.Apply("rule " + finterpAssmName)); proofSb.AppendLine("apply (rule Aux)"); proofSb.AppendLine("apply (rule dag_lemma_assms_same)"); proofSb.AppendLine("unfolding state_well_typed_def"); proofSb.AppendLine("apply (intro conjI)"); proofSb.AppendLine("using " + paramsLocalsAssmName + " apply simp"); proofSb.AppendLine("using " + constsGlobalsAssmName + " apply simp"); proofSb.AppendLine("using " + constsGlobalsAssmName + " " + oldGlobalAssmName + " apply simp"); proofSb.AppendLine("using " + binderEmptyAssmName + " apply simp"); proofSb.AppendLine(ProofUtil.Apply("rule " + passificationEndToEndLemma)); //TODO: don't hardcode this proofSb.AppendLine("unfolding glue_proof_def"); proofSb.AppendLine("apply (intro conjI)"); proofSb.AppendLine("apply assumption"); proofSb.AppendLine("using " + vcAssmName + " apply simp"); proofSb.AppendLine("using " + closedAssmName + " apply simp"); proofSb.AppendLine("using " + nonEmptyTypesAssmName + " apply simp"); proofSb.AppendLine(ProofUtil.Apply("rule " + finterpAssmName)); proofSb.AppendLine("using " + axiomAssmName + " apply simp"); proofSb.AppendLine("using " + paramsLocalsAssmName + " apply simp"); proofSb.AppendLine("using " + constsGlobalsAssmName + " apply simp"); proofSb.AppendLine("using " + binderEmptyAssmName + " apply simp"); proofSb.AppendLine("using " + oldGlobalAssmName + " apply simp"); proofSb.AppendLine("using " + preconditionsAssmName + " apply simp"); proofSb.AppendLine("done"); proofSb.AppendLine("qed"); var helperLemmaName = "end_to_end_theorem_aux"; var helperLemma = new LemmaDecl( helperLemmaName, LemmaContext(cfg, vcAssm), CfgToDagLemmaManager.CfgLemmaConclusion(boogieContext, programAccessor.PostconditionsDecl(), finalNodeOrReturn, finalState), new Proof(new List <string> { proofSb.ToString() }) ); result.Add(helperLemma); //transform end to end theorem to a compact representation var endToEndLemma = new LemmaDecl( "end_to_end_theorem", ContextElem.CreateWithAssumptions(new List <Term> { vcAssm }, new List <string> { "VC" }), ProcedureIsCorrect( programAccessor.FunctionsDecl(), IsaCommonTerms.TermIdentFromName(programAccessor.ConstsDecl()), IsaCommonTerms.TermIdentFromName(programAccessor.GlobalsDecl()), programAccessor.AxiomsDecl(), programAccessor.ProcDecl()), new Proof( new List <string> { ProofUtil.Apply(ProofUtil.Rule(ProofUtil.OF("end_to_end_util", helperLemmaName))), "apply assumption " + "using VC apply simp " + " apply assumption+", ProofUtil.By("simp_all add: exprs_to_only_checked_spec_1 exprs_to_only_checked_spec_2 " + programAccessor.ProcDeclName() + "_def " + programAccessor.CfgDeclName() + "_def") } )); result.Add(endToEndLemma); return(result); }
public static Theory PassificationProof( string theoryName, string boogieToVcTheoryName, bool generateEndToEndLemma, LemmaDecl boogieToVcLemma, Term vcAssm, CFGRepr beforePassificationCfg, IDictionary <Block, Block> nonPassiveToPassiveBlock, PassiveRelationGen relationGen, IProgramAccessor beforePassiveProgAccess, IProgramAccessor passiveProgAccess, BoogieMethodData beforePassiveData, IVariableTranslationFactory beforePassiveFactory, IVariableTranslationFactory passiveFactory) { var varContextName = "\\<Lambda>1"; var passiveVarContextName = "\\<Lambda>2"; var varContextNonPassivePassive = Tuple.Create(varContextName, passiveVarContextName); var oldGlobalVars = GetOldGlobalVariables(beforePassificationCfg); var oldRelationData = OldRelation( oldGlobalVars, beforePassiveFactory.CreateTranslation().VarTranslation, out var oldRelListDecl); var passificationProofDecls = new List <OuterDecl>(); passificationProofDecls.AddRange(oldRelListDecl); passificationProofDecls.AddRange(oldRelationData.VarToLookupLemma.Values); if (oldRelationData.VarToLookupLemma.Any()) { passificationProofDecls.Add(new LemmasDecl(allOldLookupLemmasName, oldRelationData.VarToLookupLemma.Values.Select(lemma => lemma.Name).ToList())); } var beforePassiveLemmaManager = new PassificationLemmaManager( beforePassificationCfg, nonPassiveToPassiveBlock, beforePassiveProgAccess, passiveProgAccess, varContextNonPassivePassive, oldRelationData, relationGen, beforePassiveFactory, passiveFactory ); var lemmaNamer = new IsaUniqueNamer(); var varContextAbbrev = new AbbreviationDecl( varContextName, new Tuple <IList <Term>, Term>(new List <Term>(), beforePassiveProgAccess.VarContext()) ); var passiveVarContextAbbrev = new AbbreviationDecl( passiveVarContextName, new Tuple <IList <Term>, Term>(new List <Term>(), passiveProgAccess.VarContext()) ); passificationProofDecls.Add(varContextAbbrev); passificationProofDecls.Add(passiveVarContextAbbrev); passificationProofDecls.AddRange(beforePassiveLemmaManager.Prelude()); var cfgLemmas = new List <OuterDecl>(); foreach (var block in beforePassificationCfg.GetBlocksBackwards()) { var localAndCfgLemma = beforePassiveLemmaManager.GenerateBlockLemma( block, GetLemmaName(block, lemmaNamer), b => GetCfgLemmaName(b, lemmaNamer)); passificationProofDecls.Add(localAndCfgLemma.Item1); cfgLemmas.Add(localAndCfgLemma.Item2); } //add cfg lemmas at the end passificationProofDecls.AddRange(cfgLemmas); if (generateEndToEndLemma) { var endToEnd = new PassificationEndToEnd(); passificationProofDecls.AddRange(endToEnd.EndToEndProof( GetCfgLemmaName(beforePassificationCfg.entry, lemmaNamer), boogieToVcTheoryName + "." + boogieToVcLemma.Name, vcAssm, beforePassiveProgAccess, passiveProgAccess, varContextNonPassivePassive, oldRelationData, beforePassificationCfg, relationGen.LiveVarsBeforeBlock(beforePassificationCfg.entry), passiveFactory.CreateTranslation().VarTranslation )); } var imports = new List <string> { "Boogie_Lang.Semantics", "Boogie_Lang.Util", beforePassiveProgAccess.TheoryName(), passiveProgAccess.TheoryName(), "Boogie_Lang.PassificationML", boogieToVcTheoryName }; if (generateEndToEndLemma) { imports.Add("Boogie_Lang.PassificationEndToEnd"); } return(new Theory(theoryName, imports, passificationProofDecls)); }
//return information at beginning of each block and store information at end of each block in out parameter //only store information if it is live public static IDictionary <Block, IDictionary <Variable, Expr> > ConstantVariableInformation(CFGRepr cfg, out IDictionary <Block, IDictionary <Variable, Expr> > constantExit) { var constantEntry = new Dictionary <Block, IDictionary <Variable, Expr> >(); constantExit = new Dictionary <Block, IDictionary <Variable, Expr> >(); foreach (var b in cfg.GetBlocksForwards()) { var bEntry = constantEntry.ContainsKey(b) ? constantEntry[b] : null; var bExit = ConstantExit(b, bEntry); constantExit.Add(b, bExit); foreach (var bSucc in cfg.GetSuccessorBlocks(b)) { //propagate constant information if (constantEntry.TryGetValue(bSucc, out var succEntry)) { //bSucc has multiple predecessors --> consolidate constant information constantEntry[bSucc] = Consolidate(bExit, succEntry); } else { constantEntry.Add(bSucc, bExit); } } } return(constantEntry); }
public IDictionary <Block, ISet <NamedDeclaration> > GetActiveDeclsPerBlock(IDictionary <Block, VCExpr> blockToVC, IVCVarFunTranslator translator, CFGRepr cfg, out IDictionary <Block, ISet <Variable> > blockToNewVars) { var blockToDecls = new Dictionary <Block, ISet <NamedDeclaration> >(); var declCollector = new VCExprDeclCollector(); foreach (var b in cfg.GetBlocksBackwards()) { var bDecls = declCollector.CollectNamedDeclarations(blockToVC[b], translator); foreach (var b_succ in cfg.GetSuccessorBlocks(b)) { //flattening foreach (var sucDecl in blockToDecls[b_succ]) { bDecls.Add(sucDecl); } } blockToDecls[b] = bDecls; } blockToNewVars = null; return(blockToDecls); }
public static Theory ProgramToVcProof( string theoryName, bool generateEndToEndProof, CFGRepr finalCfg, CFGRepr afterPassificationCfg, IDictionary <Block, Block> afterPassiveToFinalBlock, IDictionary <Block, Block> afterPassiveToOrigBlock, IProgramAccessor passiveProgAccess, IProgramAccessor beforePassiveProgAccess, BoogieMethodData methodData, ProgramVcProofData vcProofData, IVariableTranslationFactory varFactory, TypePremiseEraserFactory eraserFactory, VCExpressionGenerator gen, out Term vcAssm, out LemmaDecl endToEndLemma) { var lemmaNamer = new IsaUniqueNamer(); var passiveLemmaManager = new VcPhaseLemmaManager( vcProofData.VcBoogieInfo.VcInst, methodData, vcProofData.VcFunctions, passiveProgAccess.BlockInfo(), varFactory); var afterPassiveReachableBlocks = ReachableBlocks(afterPassificationCfg); var finalProgramLemmas = GenerateVCLemmas(afterPassificationCfg, finalCfg, afterPassiveToFinalBlock, afterPassiveToOrigBlock, afterPassiveReachableBlocks, passiveLemmaManager, vcProofData.VcHintManager, lemmaNamer); var cfgProgramLemmas = GenerateCfgLemmas(afterPassificationCfg, finalCfg, afterPassiveToFinalBlock, afterPassiveReachableBlocks, finalProgramLemmas, passiveLemmaManager, passiveProgAccess.CfgDecl(), lemmaNamer); var afterPassificationDecls = new List <OuterDecl>(); foreach (var v in finalProgramLemmas.Values) { afterPassificationDecls.AddRange(v); } afterPassificationDecls.AddRange(cfgProgramLemmas.Values); var afterPassificationLocale = GenerateLocale("passification", passiveLemmaManager, afterPassificationDecls); var passiveOuterDecls = new List <OuterDecl> { vcProofData.VcLocale }; passiveOuterDecls.Add(afterPassificationLocale); //generate axiom var axiomUniqueNamer = new IsaUniqueNamer(); var axId = 0; var axiomToLemma = new Dictionary <Axiom, OuterDecl>(); var vcRewriteLemmaGen = new VcRewriteLemmaGen(eraserFactory, VCExprToIsaTranslator.CreateNameBasedTranslator(new IsaUniqueNamer())); var vcAxiomLemmaManager = new VcAxiomLemmaManager( vcProofData.VcBoogieInfo.VcInstAxiom, methodData, vcProofData.VcFunctions, vcRewriteLemmaGen, varFactory); var axiomLocaleRequiredDecls = new List <OuterDecl>(); foreach (var axiom in vcProofData.VcBoogieInfo.VcAxiomsInfo) { if (axiom is VcBoogieAxiomInfo vcBoogieAxiom) { var axiomVcLemma = vcAxiomLemmaManager.AxiomVcLemma( axiomUniqueNamer.GetName(axiom, "axiom_vc_" + axId), vcBoogieAxiom.Axiom, vcBoogieAxiom.Expr, out var requiredDecls); axiomToLemma.Add(vcBoogieAxiom.Axiom, axiomVcLemma); axiomLocaleRequiredDecls.AddRange(requiredDecls); } } /* we add the required declarations for the axiom locale to the outer theory, since the axiom locale fixes variables that could clash * with the declarations */ passiveOuterDecls.AddRange(axiomLocaleRequiredDecls); var axiomLocale = GenerateLocale("axioms", vcAxiomLemmaManager, axiomToLemma.Values.ToList()); passiveOuterDecls.Add(axiomLocale); if (generateEndToEndProof) { var endToEnd = new EndToEndVCProof( methodData, passiveProgAccess, vcProofData.VcFunctions, vcProofData.VcBoogieInfo, afterPassificationCfg, finalCfg, afterPassificationLocale.Name + "." + cfgProgramLemmas[afterPassificationCfg.entry].Name, axiomLocale.Name, ax => axiomLocale.Name + "." + axiomToLemma[ax].Name, varFactory, vcProofData.VcTranslator, eraserFactory, gen); passiveOuterDecls.AddRange(endToEnd.GenerateProof(out vcAssm, out endToEndLemma)); } else { vcAssm = null; endToEndLemma = null; } return (new Theory(theoryName, new List <string> { "Boogie_Lang.Semantics", "Boogie_Lang.Util", "Boogie_Lang.VCHints", "Boogie_Lang.VCPhaseML", passiveProgAccess.TheoryName(), beforePassiveProgAccess.TheoryName() }, passiveOuterDecls)); }
/** * cases: * 1) is loop head block * 2) is back edge block * 3) successor is loop head block * * any combination is possible */ public static Theory CfgToDagProof( PhasesTheories phasesTheories, bool generateEndToEndLemma, Term vcAssm, CFGRepr beforeDagCfg, CFGRepr afterDagCfg, Block afterUniqueExit, BoogieMethodData beforeDagData, CfgToDagHintManager hintManager, IDictionary <Block, Block> beforeToAfter, IProgramAccessor beforeDagProgAccess, IProgramAccessor afterDagProgAccess, IVariableTranslationFactory varFactory) { var afterToBefore = beforeToAfter.InverseDict(); //track mapping from blocks to loops that the block is contained in and for which it is not the loop head IDictionary <Block, IList <Block> > blocksToLoops = new Dictionary <Block, IList <Block> >(); foreach (var afterBlock in afterDagCfg.GetBlocksBackwards()) { if (afterToBefore.TryGetValue(afterBlock, out var beforeBlock)) { var loops = new HashSet <Block>(); foreach (var bSuc in beforeDagCfg.GetSuccessorBlocks(beforeBlock)) { if (blocksToLoops.TryGetValue(bSuc, out var loopsSuc)) { //if successor inside of a loop L and the block is not the loop head of L, then the block is also inside L foreach (var loopSuc in loopsSuc) { if (!loopSuc.Equals(beforeBlock)) { loops.Add(loopSuc); } } } } /* a node is inside all loops for which it has an out-going backedge * if a node has a backedge to itself (i.e., it is also a loop head), then we do not add this loop */ if (hintManager.TryIsBackedgeNode(beforeBlock, out var backedgeLoops)) { foreach (var backedgeLoop in backedgeLoops) { if (beforeBlock != backedgeLoop) { loops.Add(backedgeLoop); } } } var loopsList = loops.ToList(); blocksToLoops.Add(beforeBlock, loopsList); } } var varContextName = "\\<Lambda>1"; var varContextAbbrev = new AbbreviationDecl( varContextName, new Tuple <IList <Term>, Term>(new List <Term>(), beforeDagProgAccess.VarContext()) ); var funContextWfName = "Wf_Fun"; var boogieContext = new BoogieContextIsa( IsaCommonTerms.TermIdentFromName("A"), IsaCommonTerms.TermIdentFromName("M"), IsaCommonTerms.TermIdentFromName(varContextName), IsaCommonTerms.TermIdentFromName("\\<Gamma>"), IsaCommonTerms.EmptyList); var lemmaManager = new CfgToDagLemmaManager( beforeDagProgAccess, afterDagProgAccess, boogieContext, afterDagCfg, funContextWfName, hintManager, blocksToLoops, beforeToAfter, beforeDagData, afterUniqueExit, varFactory); var lemmaNamer = new IsaUniqueNamer(); var outerDecls = new List <OuterDecl>(); outerDecls.Add(varContextAbbrev); outerDecls.Add(new DeclareDecl("Nat.One_nat_def[simp del]")); if (afterUniqueExit != null) { outerDecls.AddRange(lemmaManager.UnifiedExitLemma(GetCfgLemmaName(afterUniqueExit, lemmaNamer))); } foreach (var afterBlock in afterDagCfg.GetBlocksBackwards()) { if (afterToBefore.TryGetValue(afterBlock, out var beforeBlock)) { //if the node's only edge is a backedge, then an "assume false" will be added var singleCutEdge = hintManager.TryIsBackedgeNode(beforeBlock, out var _) && beforeDagCfg.NumOfSuccessors(beforeBlock) == 1; var(localLemmas, cfgLemma) = lemmaManager.BlockLemma( beforeBlock, afterBlock, beforeDagCfg.GetSuccessorBlocks(beforeBlock), block => GetLemmaName(block, lemmaNamer), block => GetCfgLemmaName(block, lemmaNamer), singleCutEdge ); outerDecls.AddRange(localLemmas); outerDecls.Add(cfgLemma); } else { //block was added as part of transformation if (afterBlock == afterDagCfg.entry) { //entry lemma handled elsewhere continue; } var afterBlockSuccessors = afterDagCfg.GetSuccessorBlocks(afterBlock); var afterBlockSuccessorsList = afterBlockSuccessors.ToList(); if (!afterBlockSuccessorsList.Any()) { //this must be the unique node if (afterUniqueExit == null) { throw new ProofGenUnexpectedStateException( "unique exit block added, but only exit block existed before cfg-to-dag"); } continue; } if (afterBlockSuccessorsList.Count != 1) { throw new ProofGenUnexpectedStateException( "Block added in CFG-to-DAG phase does not have a unique successor"); } var afterUniqueSuc = afterBlockSuccessorsList.First(); if (afterToBefore.TryGetValue(afterUniqueSuc, out var beforeUniqueSuc)) { hintManager.IsLoopHead(beforeUniqueSuc, out var hint); var lemma = lemmaManager.NewBlockLemma( GetCfgLemmaName(afterBlock, lemmaNamer), afterBlock, afterUniqueSuc, hint ); outerDecls.Add(lemma); } else if (hintManager.IsNewBackedgeBlock(afterBlock, out var loopHeadHint)) { if (afterDagCfg.GetSuccessorBlocks(afterUniqueSuc).Any()) { throw new ProofGenUnexpectedStateException( "New backedge node has successor that is not the exit node."); } //afterUniqueSuc is a successor to a backedge node for which all edges were eliminated var lemma = lemmaManager.NewBlockLemma( GetCfgLemmaName(afterBlock, lemmaNamer), afterBlock, null, loopHeadHint ); outerDecls.Add(lemma); } else { throw new ProofGenUnexpectedStateException( "CFG-to-DAG: Unique successor of added block cannot be mapped to original block"); } } } var entryLemma = lemmaManager.EntryLemma("entry_lemma", beforeDagCfg.entry, afterDagCfg.entry, b => GetCfgLemmaName(b, lemmaNamer)); outerDecls.Add(entryLemma); var absValType = new VarType("a"); var cfgToDagLemmasLocale = new LocaleDecl( "cfg_to_dag_lemmas", new ContextElem( new List <Tuple <TermIdent, TypeIsa> > { Tuple.Create((TermIdent)boogieContext.absValTyMap, IsaBoogieType.AbstractValueTyFunType(absValType)), Tuple.Create((TermIdent)boogieContext.funContext, IsaBoogieType.FunInterpType(absValType)) }, new List <Term> { IsaBoogieTerm.FunInterpWf(boogieContext.absValTyMap, beforeDagProgAccess.FunctionsDecl(), boogieContext.funContext) }, new List <string> { funContextWfName } ), outerDecls ); var theoryOuterDecls = new List <OuterDecl>(); theoryOuterDecls.Add(cfgToDagLemmasLocale); if (generateEndToEndLemma) { var endToEndManager = new CfgToDagEndToEnd(); var endToEndDecls = endToEndManager.EndToEndProof( cfgToDagLemmasLocale.Name + "." + entryLemma.Name, phasesTheories.EndToEndLemmaName(PhasesTheories.Phase.Passification, true), vcAssm, beforeDagProgAccess, beforeDagCfg ); theoryOuterDecls.AddRange(endToEndDecls); } return(new Theory( phasesTheories.TheoryName(PhasesTheories.Phase.CfgToDag), new List <string> { "Boogie_Lang.Semantics", "Boogie_Lang.Util", "Boogie_Lang.BackedgeElim", "Boogie_Lang.TypingML", beforeDagProgAccess.TheoryName(), afterDagProgAccess.TheoryName(), phasesTheories.TheoryName(PhasesTheories.Phase.Passification), phasesTheories.TheoryName(PhasesTheories.Phase.Vc) }, theoryOuterDecls )); }
//assume that block identities in the two CFGs are the same (only edges may be different) private static IDictionary <Block, IList <OuterDecl> > GenerateVCLemmas( CFGRepr afterPassificationCfg, CFGRepr finalCfg, IDictionary <Block, Block> afterPassiveToFinalBlock, IDictionary <Block, Block> afterPassiveToOrigBlock, HashSet <Block> reachableBlocks, VcPhaseLemmaManager vcPhaseLemmaManager, VCHintManager vcHintManager, IsaUniqueNamer lemmaNamer) { var blockToLemmaDecls = new Dictionary <Block, IList <OuterDecl> >(); foreach (var bAfterPassive in afterPassificationCfg.GetBlocksBackwards()) { var result = new List <OuterDecl>(); if (afterPassiveToFinalBlock.TryGetValue(bAfterPassive, out var bFinal)) { string vcHintsName = null; if (vcHintManager.TryGetHints(afterPassiveToOrigBlock[bAfterPassive], out var hints, out var requiredDecls)) { //FIXME potential val name clash vcHintsName = GetLemmaName(bAfterPassive, lemmaNamer) + "_hints"; var code = MLUtil.DefineVal(vcHintsName, MLUtil.MLList(hints)); //required declarations must be added first result.AddRange(requiredDecls); result.Add(new MLDecl(code)); } result.Add(vcPhaseLemmaManager.GenerateBlockLemma( bAfterPassive, bFinal, finalCfg.GetSuccessorBlocks(bFinal), GetLemmaName(bFinal, lemmaNamer), vcHintsName)); //do not use identity of final CFG block to be consistent with other branches blockToLemmaDecls.Add(bAfterPassive, result); } else if (reachableBlocks.Contains(bAfterPassive)) { //block was removed after peephole but is reachable before peephole if (bAfterPassive.Cmds.Count == 0) { //find the successors of b in the final cfg (i.e., the first non-empty reachable blocks) var nonEmptyReachableSuccessors = GetNonEmptyReachableSuccessors(bAfterPassive, afterPassificationCfg, finalCfg, afterPassiveToFinalBlock); //add lemma var decls = new List <OuterDecl> { vcPhaseLemmaManager.GenerateEmptyBlockLemma( bAfterPassive, nonEmptyReachableSuccessors.Select(b => afterPassiveToFinalBlock[b]), GetLemmaName(bAfterPassive, lemmaNamer)) }; blockToLemmaDecls.Add(bAfterPassive, decls); } else { throw new ProofGenUnexpectedStateException( "Non-empty reachable block removed during peep-hole"); } } } return(blockToLemmaDecls); }
public IProgramAccessor GetIsaProgram( string theoryName, string procName, BoogieMethodData methodData, IsaProgramGeneratorConfig config, IVariableTranslationFactory varTranslationFactory, CFGRepr cfg, out IList <OuterDecl> decls, bool generateMembershipLemmas = true, bool onlyGlobalData = false ) { this.varTranslationFactory = varTranslationFactory; varTranslation = varTranslationFactory.CreateTranslation(); cmdIsaVisitor = new MultiCmdIsaVisitor(varTranslationFactory); /* * Term program = IsaBoogieTerm.Program(IsaCommonTerms.TermIdentFromName(funcs.name), * new TermList(new List<Term>()), * new TermList(new List<Term>()), * IsaCommonTerms.TermIdentFromName(axiomsDecl.name), * new List<Term>() { method }); * * var list = new List<Tuple<IList<Term>, Term>> * { * new Tuple<IList<Term>, Term>(new List<Term>(), program) * }; */ //OuterDecl programDefinition = new DefDecl("ProgramM", new Tuple<IList<Term>, Term>(new List<Term>(), program)); decls = new List <OuterDecl>(); var isaGlobalProgramRepr = new IsaGlobalProgramRepr( FunctionDeclarationsName(), AxiomDeclarationsName(), VariableDeclarationsName("globals"), VariableDeclarationsName("constants") ); var globalsMax = methodData.Constants.Count() + methodData.GlobalVars.Count() - 1; // assume single versioning and order on constants, globals, params, locals var localsMin = globalsMax + 1; if (globalsMax < 0) { globalsMax = 0; } MembershipLemmaManager membershipLemmaManager; if (onlyGlobalData) { membershipLemmaManager = new MembershipLemmaManager( isaGlobalProgramRepr, globalsMax, varTranslationFactory, theoryName); } else { var outEdges = GetOutEdgesIsa(procName, cfg, out var edgeLemmas); var blockInfo = BlockToInfo(theoryName, procName, cfg, edgeLemmas); var isaProgramRepr = new IsaProgramRepr( isaGlobalProgramRepr, PreconditionDeclarationName(), PostconditionDeclarationName(), VariableDeclarationsName("params"), VariableDeclarationsName("locals"), cfgName, procDefName); membershipLemmaManager = new MembershipLemmaManager(config, isaProgramRepr, blockInfo, Tuple.Create(globalsMax, localsMin), varTranslationFactory, theoryName); var nodesToBlocks = GetNodeToBlocksIsa(cfg, blockInfo.BlockCmdsDefs); decls.AddRange(blockInfo.BlockCmdsDefs.Values); Term entry = new IntConst(BigNum.FromInt(cfg.GetUniqueIntLabel(cfg.entry))); var methodBodyCFG = IsaBoogieTerm.MethodCFGBody( entry, IsaCommonTerms.TermIdentFromName(outEdges.Name), IsaCommonTerms.TermIdentFromName(nodesToBlocks.Name) ); var methodBodyDecl = GetMethodBodyCFGDecl(procName, methodBodyCFG); decls.AddRange( new List <OuterDecl> { outEdges, nodesToBlocks, methodBodyDecl }); decls.AddRange(blockInfo.BlockCmdsLemmas.Values); decls.AddRange(blockInfo.BlockOutEdgesLemmas.Values); if (config.specsConfig != SpecsConfig.None) { OuterDecl preconditions; OuterDecl postconditions; if (config.specsConfig == SpecsConfig.AllPreCheckedPost) { preconditions = GetExprListIsa(PreconditionDeclarationName(), methodData.Preconditions.Select(pre => pre.Item1)); postconditions = GetExprListIsa(PostconditionDeclarationName(), methodData.Postconditions.Where(post => !post.Item2).Select(post => post.Item1)); } else { preconditions = GetExprListIsa(PreconditionDeclarationName(), methodData.Preconditions); postconditions = GetExprListIsa(PostconditionDeclarationName(), methodData.Postconditions); } decls.Add(preconditions); decls.Add(postconditions); } if (config.generateParamsAndLocals) { decls.Add(GetVariableDeclarationsIsa("params", methodData.InParams)); decls.Add(GetVariableDeclarationsIsa("locals", methodData.Locals)); } /* membership lemmas might still be added even if the parameter and local variable definitions are not generated * at this point (since the variable context may still be different, which requires other lookup lemmas) */ if (generateMembershipLemmas) { membershipLemmaManager.AddVariableMembershipLemmas(methodData.InParams, VarKind.ParamOrLocal); membershipLemmaManager.AddVariableMembershipLemmas(methodData.Locals, VarKind.ParamOrLocal); } } if (config.generateAxioms) { decls.Add(GetAxioms(methodData.Axioms)); if (generateMembershipLemmas) { membershipLemmaManager.AddAxiomMembershipLemmas(methodData.Axioms); } } if (config.generateFunctions) { decls.Add(GetFunctionDeclarationsIsa(methodData.Functions)); if (generateMembershipLemmas) { membershipLemmaManager.AddFunctionMembershipLemmas(methodData.Functions); } } if (config.generateGlobalsAndConstants) { decls.Add(GetVariableDeclarationsIsa("globals", methodData.GlobalVars)); decls.Add(GetVariableDeclarationsIsa("constants", methodData.Constants)); } if (generateMembershipLemmas) { membershipLemmaManager.AddVariableMembershipLemmas(methodData.GlobalVars, VarKind.Global); membershipLemmaManager.AddVariableMembershipLemmas(methodData.Constants, VarKind.Constant); decls.AddRange(membershipLemmaManager.OuterDecls()); } if (config.specsConfig != SpecsConfig.None) { DefDecl methodDef = MethodDefinition(membershipLemmaManager, methodData, config.specsConfig); decls.Add(methodDef); } return(membershipLemmaManager); }
//cfg must be acyclic public static IDictionary <Block, IEnumerable <Variable> > ComputeLiveVariables(CFGRepr cfg, BoogieMethodData methodData) { var liveVarsBefore = new Dictionary <Block, IEnumerable <Variable> >(); var allVarsSet = new HashSet <Variable>(methodData.AllVariables()); foreach (var b in cfg.GetBlocksBackwards()) { var bCurLiveVars = new HashSet <Variable>(); foreach (var bSuc in cfg.GetSuccessorBlocks(b)) { bCurLiveVars.UnionWith(liveVarsBefore[bSuc]); } for (var idx = b.cmds.Count - 1; idx >= 0; idx--) { UpdateLiveSet(b.cmds[idx], bCurLiveVars); } //due to the VariableCollector's implementation bound variables may also have been included bCurLiveVars.RemoveWhere(v => !allVarsSet.Contains(v)); liveVarsBefore.Add(b, bCurLiveVars); } return(liveVarsBefore); }
public static LocaleDecl ConvertVC( string localeName, VCExpr vc, IEnumerable <VCExpr> vcAxioms, IActiveDeclGenerator activeDeclGenerator, Boogie2VCExprTranslator translator, TypeAxiomBuilderPremisses axiomBuilder, BoogieMethodData methodData, CFGRepr cfg, out VCInstantiation <Block> vcinst, out VCInstantiation <VCExpr> vcinstAxiom, out IVCVarFunTranslator vcTranslator, out IEnumerable <Function> vcTypeFunctions) { var vcLet = vc as VCExprLet; Contract.Assert(vcLet != null); var uniqueNamer = new IsaUniqueNamer(); var blockToVC = VCBlockExtractor.BlockToVCMapping(vcLet, cfg); var declCollector = new VCFunDeclCollector(); var funToVCfun = declCollector.CollectFunDeclarations(new List <VCExpr> { vc }.Concat(vcAxioms), methodData.Functions); IVCVarFunTranslator varTranslator = new VCVarFunTranslator(methodData.AllVariables(), funToVCfun, translator, axiomBuilder); var activeDeclsPerBlock = activeDeclGenerator.GetActiveDeclsPerBlock(blockToVC, varTranslator, cfg, out var blockToNewVars); #region temporary: extend vc instantiation to support vc functions IList <Function> otherFunctions = new List <Function>(); ISet <Function> otherFunctionsSet = new HashSet <Function>(); foreach (var decl in activeDeclsPerBlock[cfg.entry]) { if (decl is Function fun && !varTranslator.TranslateBoogieFunction(fun, out _)) { otherFunctions.Add(fun); otherFunctionsSet.Add(fun); } } //also record functions that are used elswhere (type axiom related functions) var collector = new VCExprDeclCollector(); var vcExprs = vcAxioms.ToList(); foreach (var ax in vcExprs) { var decls = collector.CollectNamedDeclarations(ax, varTranslator); foreach (var d in decls) { if (d is Function fun && !varTranslator.TranslateBoogieFunction(fun, out _) && !otherFunctions.Contains(d)) { otherFunctions.Add(fun); } } } #endregion IDictionary <Block, IList <NamedDeclaration> > activeDeclsPerBlockSorted = SortActiveDecls(activeDeclsPerBlock, methodData.Functions.Union(otherFunctions), varTranslator, out var activeVarsPerBlock); var blockToNewVCVars = ConvertVariableToVCExpr(blockToNewVars, varTranslator); var blockToIsaTranslator = new VCBlockToIsaTranslator(uniqueNamer); var blockToVCExpr = blockToIsaTranslator.IsaDefsFromVC(blockToVC, activeVarsPerBlock, cfg, blockToNewVCVars); //add vc definitions of blocks in correct order IList <OuterDecl> vcOuterDecls = new List <OuterDecl>(); foreach (var block in cfg.GetBlocksBackwards()) { vcOuterDecls.Add(blockToVCExpr[block]); } vcinst = new VCInstantiation <Block>(blockToVCExpr, activeDeclsPerBlockSorted, localeName); /* * * //reason for using second reference: cannot use out parameters in lambda expressions * var vcinstInternal = vcinst; * * LemmaDecl vcCorrectLemma = new LemmaDecl("vc_correct", * new TermApp(vcinstInternal.GetVCObjRef(cfg.entry, false), * activeVarsPerBlock[cfg.entry].Select(v => (Term) IsaCommonTerms.TermIdentFromName(uniqueNamer.GetName(v, v.Name))).ToList()), * new Proof( * new List<string>() { * "apply (simp only: " + * cfg.GetBlocksForwards().Select(b => vcinstInternal.GetVCObjNameRef(b, false) + "_def").Concat(" ") + ")", + "oops" + } + )); + + vcOuterDecls.Add(vcCorrectLemma); */ //axioms var activeDeclsPerAxiom = VCInstAxioms(vcExprs, varTranslator); IDictionary <VCExpr, IList <NamedDeclaration> > activeDeclsPerAxiomSorted = SortActiveDecls(activeDeclsPerAxiom, methodData.Functions.Union(otherFunctions), varTranslator, out var activeVarsPerAxiom); var axiomToDef = new Dictionary <VCExpr, DefDecl>(); var vcExprIsaTranslator = new VCExprToIsaTranslator(uniqueNamer); if (activeDeclsPerAxiomSorted.Count != vcExprs.Count()) { throw new ProofGenUnexpectedStateException(typeof(VCToIsaInterface), "count not in-sync"); } var axId = 0; foreach (var vcAx in activeDeclsPerAxiomSorted.Keys) { IList <Term> args = activeVarsPerAxiom[vcAx].Select(v => vcExprIsaTranslator.Translate(v)).ToList(); var rhs = vcExprIsaTranslator.Translate(vcAx); var def = new DefDecl("vcax_" + axId, new Tuple <IList <Term>, Term>(args, rhs)); axiomToDef.Add(vcAx, def); axId++; } vcinstAxiom = new VCInstantiation <VCExpr>(axiomToDef, activeDeclsPerAxiomSorted, localeName); vcOuterDecls.AddRange(axiomToDef.Values); var vcFunctions = methodData.Functions.Where(f => varTranslator.TranslateBoogieFunction(f, out var result)) .Select(f => { if (varTranslator.TranslateBoogieFunction(f, out var result)) { return(result); } throw new InvalidOperationException(); }).Union(otherFunctions); vcTranslator = varTranslator; vcTypeFunctions = otherFunctions; return(new LocaleDecl(localeName, ContextElem.CreateWithFixedVars(GetVarsInVC(vcFunctions, uniqueNamer)), vcOuterDecls)); }
public IDictionary <Block, ISet <NamedDeclaration> > GetActiveDeclsPerBlock(IDictionary <Block, VCExpr> blockToVC, IVCVarFunTranslator translator, CFGRepr cfg, out IDictionary <Block, ISet <Variable> > blockToNewVars) { var blockToDefinedDecls = new Dictionary <Block, ISet <NamedDeclaration> >(); foreach (var b in cfg.GetBlocksForwards()) { blockToDefinedDecls.Add(b, new HashSet <NamedDeclaration>()); } var declCollector = new VCExprDeclCollector(); var blockToNamedDecls = new Dictionary <Block, ISet <NamedDeclaration> >(); //compute all named declarations in the VC for each block b which have been used before b is reached foreach (var b in cfg.GetBlocksForwards()) { var bDecls = declCollector.CollectNamedDeclarations(blockToVC[b], translator); blockToNamedDecls.Add(b, bDecls); foreach (var bSucc in cfg.GetSuccessorBlocks(b)) { blockToDefinedDecls[bSucc].UnionWith(bDecls); blockToDefinedDecls[bSucc].UnionWith(blockToDefinedDecls[b]); } } //compute all named declarations in the VC for each block b that are in any path reached from b and which were defined in any path reaching b //named declarations which are not variables are trivially defined at the beginning of the CFG var blockToActiveDecls = new Dictionary <Block, ISet <NamedDeclaration> >(); blockToNewVars = new Dictionary <Block, ISet <Variable> >(); foreach (var b in cfg.GetBlocksBackwards()) { var bDecls = blockToNamedDecls[b]; ISet <NamedDeclaration> oldActiveDecls = new HashSet <NamedDeclaration>(); ISet <Variable> newDecls = new HashSet <Variable>(); foreach (var d in bDecls) { if (d is Variable v && !blockToDefinedDecls[b].Contains(d)) { newDecls.Add(v); }