/////////////////////////////////////////////////////////////////////// // MAKING ATOMIC STEPS /////////////////////////////////////////////////////////////////////// private void DetermineAtomicPaths() { allPCs = new List <ArmadaPC>(); symbols.AllMethods.AppendAllPCs(allPCs); var tauPathPrefix = new AtomicPathPrefix(this, new List <NextRoutine> { symbols.TauNextRoutine }, true, null); tauPath = new AtomicPath(tauPathPrefix); atomicPaths = new List <AtomicPath> { tauPath }; rootPathPrefixesByPC = new Dictionary <ArmadaPC, List <AtomicPathPrefix> >(); foreach (var startPC in allPCs) { rootPathPrefixesByPC[startPC] = new List <AtomicPathPrefix>(); if (GetPCAtomicType(startPC) != PCAtomicType.Nonyielding) { List <NextRoutine> nextRoutines; if (pcToNextRoutines.TryGetValue(startPC, out nextRoutines)) { foreach (var nextRoutine in nextRoutines) { var rootAtomicPathPrefix = new AtomicPathPrefix(this, new List <NextRoutine> { nextRoutine }, false, null); rootPathPrefixesByPC[startPC].Add(rootAtomicPathPrefix); PopulateAtomicPathPrefix(rootAtomicPathPrefix); } } } } }
protected override void GenerateLiftAtomicPathLemmaForTauPath(AtomicPath atomicPath, string typeComparison, string extraSignatureLines) { if (!canHideTau) { base.GenerateLiftAtomicPathLemmaForTauPath(atomicPath, typeComparison, extraSignatureLines); return; } var lpr = new PrefixedVarsPathPrinter(lAtomic); var hpr = new PrefixedVarsPathPrinter(hAtomic); string str = $@" lemma lemma_LiftAtomicPath_Tau(ls: LPlusState, lpath: LAtomic_Path, tid: Armada_ThreadHandle) requires InductiveInv(ls) requires LAtomic_ValidPath(ls, lpath, tid) requires lpath.LAtomic_Path_Tau? requires !IsSkippedTauPath(ls, lpath, tid) ensures var ls' := LAtomic_GetStateAfterPath(ls, lpath, tid); var hs := ConvertTotalState_LPlusH(ls); var hpath := ConvertAtomicPath_LH(ls, lpath, tid); var hs' := HAtomic_GetStateAfterPath(hs, hpath, tid); var ty := LAtomic_GetPathType(lpath); && HAtomic_GetPathType(hpath) == ty && HAtomic_ValidPath(hs, hpath, tid) && hs' == ConvertTotalState_LPlusH(ls') && ls'.s.stop_reason.Armada_NotStopped? == hs'.stop_reason.Armada_NotStopped? {{ { lpr.GetOpenValidPathInvocation(lAtomic.TauPath) } var ls' := LAtomic_GetStateAfterPath(ls, lpath, tid); var hs := ConvertTotalState_LPlusH(ls); var hpath := ConvertAtomicPath_LH(ls, lpath, tid); var hs' := ConvertTotalState_LPlusH(ls'); { hpr.GetOpenPathInvocation(hAtomic.TauPath) } var lentry := ls.s.threads[tid].storeBuffer[0]; assert CanConvertStoreBufferEntry_LH(lentry); var hentry := hs.threads[tid].storeBuffer[0]; var lmem := ls.s.mem; var hmem1 := ConvertSharedMemory_LH(L.Armada_ApplyStoreBufferEntry(lmem, lentry)); var hmem2 := H.Armada_ApplyStoreBufferEntry(ConvertSharedMemory_LH(lmem), hentry); lemma_ApplyStoreBufferEntryCommutesWithConvert(lmem, lentry, hentry, hmem1, hmem2); var alt_hs' := HAtomic_GetStateAfterPath(hs, hpath, tid); ProofCustomizationGoesHere(); assert hs'.threads[tid] == alt_hs'.threads[tid]; assert hs'.threads == alt_hs'.threads; assert hs' == alt_hs'; /* { hpr.GetAssertValidPathInvocation(hAtomic.TauPath) } */ }} "; pgp.AddLemma(str, "lift"); }
public AtomicPathPrefix(AtomicSpec i_atomicSpec, ArmadaPC pc) { atomicSpec = i_atomicSpec; nextRoutines = new List <NextRoutine>(); tau = false; startPC = endPC = pc; startType = endType = atomicSpec.GetPCAtomicType(pc); extensions = new List <AtomicPathPrefix>(); path = null; }
protected override void GenerateLiftAtomicPathLemmaForNormalPath(AtomicPath atomicPath, string typeComparison, string extraSignatureLines, string extraProof) { var isValidStepLemmaInvocations = String.Concat(atomicPath.NextRoutines .Where(nextRoutine => nextRoutine.stmt != null && nextRoutine.startPC != null && weakenedPCs.Contains(nextRoutine.startPC)) .Select((nextRoutine, idx) => $@" lemma_Step_{nextRoutine.NameSuffix}_ImpliesConvertedIsValidStep( lstates.s{idx}, lstates.s{idx+1}, lsteps.step{idx}, hsteps.step{idx}, tid); ")); base.GenerateLiftAtomicPathLemmaForNormalPath(atomicPath, typeComparison, extraSignatureLines, extraProof + "\n" + isValidStepLemmaInvocations); }
public string GetConstructorString(AtomicPath atomicPath) { if (atomicPath.NextRoutines.Where(r => r.HasFormals).Any()) { // TODO: this does not work with introduced statements with * AH.PrintError(pgp.prog, "Armada currently doesn't support introducing a non-deterministic statement."); } var str = $"{prefix}_Path_{atomicPath.Name}({prefix}_PathSteps_{atomicPath.Name}("; str += String.Join(", ", atomicPath.NextRoutines.Select(r => $"{moduleName}.Armada_Step_{r.NameSuffix}()")); str += "))"; return(str); }
public virtual string GetAssertValidPathInvocation(AtomicPath atomicPath) { string str = ""; foreach (var i in Enumerable.Range(0, atomicPath.NumNextRoutines)) { var nextRoutine = atomicPath.NextRoutines[i]; var stepPrinter = new ModuleStepPrinter(ModuleName); stepPrinter.State = atomicSpec.Low ? $"{States}.s{i}.s" : $"{States}.s{i}"; stepPrinter.NextState = atomicSpec.Low ? $"{States}.s{i + 1}.s" : $"{States}.s{i + 1}"; stepPrinter.Step = $"{Steps}.step{i}"; stepPrinter.Tid = Tid; str += stepPrinter.GetAssertValidStepInvocation(nextRoutine); } str += $@" assert {Prefix}_ValidPath_{atomicPath.Name}({State}, {Tid}, {Steps}); assert {Prefix}_ValidPath({State}, {Path}, {Tid}); assert {NextState} == {Prefix}_GetStateAfterPath({State}, {Path}, {Tid}); "; return(str); }
public virtual string GetOpenValidPathInvocation(AtomicPath atomicPath) { string str = $@" var {Steps}, {States} := lemma_{Prefix}_OpenPath_{atomicPath.Name}({State}, {Path}, {Tid}); "; /* * assert {Path} == {Prefix}_Path_{atomicPath.Name}({Steps}); * assert {Prefix}_ValidPath_{atomicPath.Name}({State}, {Tid}, {Steps}); * assert {States} == {Prefix}_GetPathStates_{atomicPath.Name}({State}, {Tid}, {Steps}); * assert {Prefix}_GetStateAfterPath({State}, {Path}, {Tid}) == {States}.s{atomicPath.NumNextRoutines}; */ foreach (var i in Enumerable.Range(0, atomicPath.NumNextRoutines)) { var nextRoutine = atomicPath.NextRoutines[i]; var stepPrinter = new ModuleStepPrinter(ModuleName); stepPrinter.State = atomicSpec.Low ? $"{States}.s{i}.s" : $"{States}.s{i}"; stepPrinter.Step = $"{Steps}.step{i}"; stepPrinter.Tid = Tid; str += stepPrinter.GetOpenValidStepInvocation(nextRoutine); } return(str); }
private void CreateFunctionsForAtomicPath(AtomicPath atomicPath) { var nextRoutines = atomicPath.NextRoutines; string str; str = $@" function {prefix}_GetPathStates_{atomicPath.Name}( s0: {typeState}, tid: Armada_ThreadHandle, steps: {prefix}_PathSteps_{atomicPath.Name} ) : {prefix}_PathStates_{atomicPath.Name} {{ "; str += String.Concat( Enumerable.Range(0, nextRoutines.Count).Select(i => $" var s{i + 1} := {getNextState}(s{i}, steps.step{i}, tid);\n") ); str += $" {prefix}_PathStates_{atomicPath.Name}("; str += String.Join(", ", Enumerable.Range(0, nextRoutines.Count + 1).Select(i => $"s{i}")); str += ") }"; pgp.AddFunction(str, auxName); str = $@" predicate {prefix}_ValidPath_{atomicPath.Name}( s: {typeState}, tid: Armada_ThreadHandle, steps: {prefix}_PathSteps_{atomicPath.Name} ) {{ var states := {prefix}_GetPathStates_{atomicPath.Name}(s, tid, steps); "; str += String.Concat(Enumerable.Range(0, nextRoutines.Count).Select(i => $@" && steps.step{i}.Armada_Step_{nextRoutines[i].NameSuffix}? && {validStep}(states.s{i}, steps.step{i}, tid) ")); str += "}"; pgp.AddPredicate(str, auxName); }
public AtomicPathPrefix(AtomicSpec i_atomicSpec, List <NextRoutine> i_nextRoutines, bool i_tau, AtomicPathPrefix parent) { atomicSpec = i_atomicSpec; nextRoutines = new List <NextRoutine>(i_nextRoutines); tau = i_tau; startPC = nextRoutines[0].startPC; endPC = nextRoutines[nextRoutines.Count - 1].endPC; startType = atomicSpec.GetPCAtomicType(startPC); endType = nextRoutines[nextRoutines.Count - 1].Stopping ? PCAtomicType.Stopping : atomicSpec.GetPCAtomicType(endPC); extensions = new List <AtomicPathPrefix>(); path = null; if (parent != null) { parent.AddExtension(this); } if (tau) { name = "Tau"; } else { name = UndefinedBehavior ? "UB_" : ""; name += $"From_{startPC.methodName}_{startPC.Name}"; // It's possible for two atomic paths to have the same start // and end PCs. But, every path has to have a distinct name, // so we sometimes have to name a path with more than just the // start and end PCs. // // One way for two atomic paths with the same start and end // PCs to differ is via returning to different PCs. For // instance, consider the following code: // // method {:atomic} A { // S1; // label L: // S2; // } // // method B { // atomic { // A(); // A(); // A(); // } // } // // Here, there are two ways to get from label L to label L: // (1) by returning from B's first call to A and then making // B's second call to A, and (2) by returning from B's second // call to A and then making B's third call to A. So, to make // sure such paths have different names, we include in the // name every returned-to PC in a step other than the last one // in the path. // // Another way for two atomic paths with the same start and // end PCs to differ is via branch outcomes. For instance, // consider the following code: // // atomic { // if P { // S1; // } // S2; // } // // Here, there are two ways to get from the beginning to the // end: via the true branch of the if (passing through // statement S1) or via the false branch. So we distinguish // the names of such paths by the branch outcomes. bool justBranched = false; for (var i = 0; i < nextRoutines.Count; ++i) { var nextRoutine = nextRoutines[i]; if (i < nextRoutines.Count - 1 && nextRoutine.nextType == NextType.Return) { var returnToPC = nextRoutine.endPC; name += $"_Via_{returnToPC.methodName}_{returnToPC.Name}"; justBranched = false; } bool branchOutcome; if (nextRoutine.TryGetBranchOutcome(out branchOutcome)) { if (!justBranched) { name += "_"; } name += (branchOutcome ? "T" : "F"); justBranched = true; } } if (endPC == null) { name += "_to_exit"; } else { name += $"_To_{endPC.methodName}_{endPC.Name}"; } } }
public static PrioritizationAttributes GetPrioritizationAttributesForLiftAtomicPath(AtomicPath lowAtomicPath, AtomicPath highAtomicPath) { if (lowAtomicPath.NextRoutines.Select(nextRoutine => nextRoutine.armadaStatement == null ? null : Printer.StatementToString(nextRoutine.armadaStatement.Stmt)).SequenceEqual( highAtomicPath.NextRoutines.Select(nextRoutine => nextRoutine.armadaStatement == null ? null : Printer.StatementToString(nextRoutine.armadaStatement.Stmt)))) { return(new PrioritizationAttributes { likelihoodOfFailure = 0 }); } return(new PrioritizationAttributes { likelihoodOfFailure = 3 }); /* * // TODO: this check assumes that corresponding nextRoutines with no associated armada statements are the same * if (lowAtomicPath.NextRoutines.Count == highAtomicPath.NextRoutines.Count) * { * bool stmtsEqual = false; * for (int i = 0; i < lowAtomicPath.NextRoutines.Count; i++) { * if (stmtsEqual) { * return new PrioritizationAttributes { likelihoodOfFailure = 0 }; * } * } * } * return new PrioritizationAttributes { likelihoodOfFailure = 3 }; */ }
public virtual string PathSteps(AtomicPath path) { return($"{State}, {Tid}, {Steps}"); }
public virtual string PathFormals(AtomicPath path) { return($"{State}:{TotalStateType}, {Tid}:Armada_ThreadHandle, {Steps}:{StepsType(path)}"); }
public virtual string CaseEntryWithUnderscores(AtomicPath path) { return($"case {Prefix}_Path_{path.Name}(_)"); }
public virtual string CaseEntry(AtomicPath path) { return($"case {Prefix}_Path_{path.Name}({ParamsParam})"); }
public virtual string StepsType(AtomicPath path) { return($"{Prefix}_PathSteps_{path.Name}"); }