diff options
Diffstat (limited to 'Source/Concurrency')
-rw-r--r-- | Source/Concurrency/App.config | 12 | ||||
-rw-r--r-- | Source/Concurrency/CivlRefinement.cs (renamed from Source/Concurrency/OwickiGries.cs) | 2418 | ||||
-rw-r--r-- | Source/Concurrency/CivlTypeChecker.cs | 1160 | ||||
-rw-r--r-- | Source/Concurrency/Concurrency.csproj | 228 | ||||
-rw-r--r-- | Source/Concurrency/LinearSets.cs | 2007 | ||||
-rw-r--r-- | Source/Concurrency/MoverCheck.cs | 1320 | ||||
-rw-r--r-- | Source/Concurrency/Program.cs | 88 | ||||
-rw-r--r-- | Source/Concurrency/Properties/AssemblyInfo.cs | 72 | ||||
-rw-r--r-- | Source/Concurrency/SimulationRelation.cs | 394 | ||||
-rw-r--r-- | Source/Concurrency/TypeCheck.cs | 724 | ||||
-rw-r--r-- | Source/Concurrency/YieldTypeChecker.cs | 731 |
11 files changed, 4830 insertions, 4324 deletions
diff --git a/Source/Concurrency/App.config b/Source/Concurrency/App.config index 84bc4207..e95ce985 100644 --- a/Source/Concurrency/App.config +++ b/Source/Concurrency/App.config @@ -1,6 +1,6 @@ -<?xml version="1.0"?>
-<configuration>
- <startup>
- <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0,Profile=Client"/>
- </startup>
-</configuration>
+<?xml version="1.0"?> +<configuration> + <startup> + <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0,Profile=Client"/> + </startup> +</configuration> diff --git a/Source/Concurrency/OwickiGries.cs b/Source/Concurrency/CivlRefinement.cs index dbd1dcbd..75ff2358 100644 --- a/Source/Concurrency/OwickiGries.cs +++ b/Source/Concurrency/CivlRefinement.cs @@ -1,1188 +1,1230 @@ -using System;
-using System.Collections;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using Microsoft.Boogie;
-using System.Diagnostics;
-using System.Diagnostics.Contracts;
-using Microsoft.Boogie.GraphUtil;
-
-namespace Microsoft.Boogie
-{
- public class MyDuplicator : Duplicator
- {
- MoverTypeChecker moverTypeChecker;
- public int layerNum;
- Procedure enclosingProc;
- Implementation enclosingImpl;
- public Dictionary<Procedure, Procedure> procMap; /* Original -> Duplicate */
- public Dictionary<Absy, Absy> absyMap; /* Duplicate -> Original */
- public Dictionary<Implementation, Implementation> implMap; /* Duplicate -> Original */
- public HashSet<Procedure> yieldingProcs;
- public List<Implementation> impls;
-
- public MyDuplicator(MoverTypeChecker moverTypeChecker, int layerNum)
- {
- this.moverTypeChecker = moverTypeChecker;
- this.layerNum = layerNum;
- this.enclosingProc = null;
- this.enclosingImpl = null;
- this.procMap = new Dictionary<Procedure, Procedure>();
- this.absyMap = new Dictionary<Absy, Absy>();
- this.implMap = new Dictionary<Implementation, Implementation>();
- this.yieldingProcs = new HashSet<Procedure>();
- this.impls = new List<Implementation>();
- }
-
- private void ProcessCallCmd(CallCmd originalCallCmd, CallCmd callCmd, List<Cmd> newCmds)
- {
- int enclosingProcLayerNum = moverTypeChecker.procToActionInfo[enclosingImpl.Proc].createdAtLayerNum;
- Procedure originalProc = originalCallCmd.Proc;
- if (moverTypeChecker.procToActionInfo.ContainsKey(originalProc))
- {
- AtomicActionInfo atomicActionInfo = moverTypeChecker.procToActionInfo[originalProc] as AtomicActionInfo;
- if (atomicActionInfo != null && atomicActionInfo.thisGate.Count > 0 && layerNum == enclosingProcLayerNum)
- {
- newCmds.Add(new HavocCmd(Token.NoToken, new List<IdentifierExpr>(new IdentifierExpr[] { Expr.Ident(dummyLocalVar) })));
- Dictionary<Variable, Expr> map = new Dictionary<Variable, Expr>();
- for (int i = 0; i < originalProc.InParams.Count; i++)
- {
- map[originalProc.InParams[i]] = callCmd.Ins[i];
- }
- Substitution subst = Substituter.SubstitutionFromHashtable(map);
- foreach (AssertCmd assertCmd in atomicActionInfo.thisGate)
- {
- newCmds.Add(Substituter.Apply(subst, assertCmd));
- }
- }
- }
- newCmds.Add(callCmd);
- }
-
- private void ProcessParCallCmd(ParCallCmd originalParCallCmd, ParCallCmd parCallCmd, List<Cmd> newCmds)
- {
- int maxCalleeLayerNum = 0;
- foreach (CallCmd iter in originalParCallCmd.CallCmds)
- {
- int calleeLayerNum = moverTypeChecker.procToActionInfo[iter.Proc].createdAtLayerNum;
- if (calleeLayerNum > maxCalleeLayerNum)
- maxCalleeLayerNum = calleeLayerNum;
- }
- if (layerNum > maxCalleeLayerNum)
- {
- for (int i = 0; i < parCallCmd.CallCmds.Count; i++)
- {
- ProcessCallCmd(originalParCallCmd.CallCmds[i], parCallCmd.CallCmds[i], newCmds);
- absyMap[parCallCmd.CallCmds[i]] = originalParCallCmd;
- }
- }
- else
- {
- newCmds.Add(parCallCmd);
- }
- }
-
- public override List<Cmd> VisitCmdSeq(List<Cmd> cmdSeq)
- {
- List<Cmd> cmds = base.VisitCmdSeq(cmdSeq);
- List<Cmd> newCmds = new List<Cmd>();
- for (int i = 0; i < cmds.Count; i++)
- {
- Cmd originalCmd = cmdSeq[i];
- Cmd cmd = cmds[i];
-
- CallCmd originalCallCmd = originalCmd as CallCmd;
- if (originalCallCmd != null)
- {
- ProcessCallCmd(originalCallCmd, cmd as CallCmd, newCmds);
- continue;
- }
-
- ParCallCmd originalParCallCmd = originalCmd as ParCallCmd;
- if (originalParCallCmd != null)
- {
- ProcessParCallCmd(originalParCallCmd, cmd as ParCallCmd, newCmds);
- continue;
- }
-
- newCmds.Add(cmd);
- }
- return newCmds;
- }
-
- public override YieldCmd VisitYieldCmd(YieldCmd node)
- {
- YieldCmd yieldCmd = base.VisitYieldCmd(node);
- absyMap[yieldCmd] = node;
- return yieldCmd;
- }
-
- public override Block VisitBlock(Block node)
- {
- Block block = base.VisitBlock(node);
- absyMap[block] = node;
- return block;
- }
-
- public override Cmd VisitCallCmd(CallCmd node)
- {
- CallCmd callCmd = (CallCmd) base.VisitCallCmd(node);
- callCmd.Proc = VisitProcedure(callCmd.Proc);
- callCmd.callee = callCmd.Proc.Name;
- absyMap[callCmd] = node;
- return callCmd;
- }
-
- public override Cmd VisitParCallCmd(ParCallCmd node)
- {
- ParCallCmd parCallCmd = (ParCallCmd) base.VisitParCallCmd(node);
- absyMap[parCallCmd] = node;
- return parCallCmd;
- }
-
- public override Procedure VisitProcedure(Procedure node)
- {
- if (!moverTypeChecker.procToActionInfo.ContainsKey(node))
- return node;
- if (!procMap.ContainsKey(node))
- {
- enclosingProc = node;
- Procedure proc = (Procedure)node.Clone();
- proc.Name = string.Format("{0}_{1}", node.Name, layerNum);
- proc.InParams = this.VisitVariableSeq(node.InParams);
- proc.Modifies = this.VisitIdentifierExprSeq(node.Modifies);
- proc.OutParams = this.VisitVariableSeq(node.OutParams);
-
- ActionInfo actionInfo = moverTypeChecker.procToActionInfo[node];
- if (actionInfo.createdAtLayerNum < layerNum)
- {
- proc.Requires = new List<Requires>();
- proc.Ensures = new List<Ensures>();
- Implementation impl;
- AtomicActionInfo atomicActionInfo = actionInfo as AtomicActionInfo;
- if (atomicActionInfo != null)
- {
- CodeExpr action = (CodeExpr)VisitCodeExpr(atomicActionInfo.thisAction);
- List<Cmd> cmds = new List<Cmd>();
- foreach (AssertCmd assertCmd in atomicActionInfo.thisGate)
- {
- cmds.Add(new AssumeCmd(Token.NoToken, (Expr)Visit(assertCmd.Expr)));
- }
- Block newInitBlock = new Block(Token.NoToken, "_init", cmds,
- new GotoCmd(Token.NoToken, new List<string>(new string[] { action.Blocks[0].Label }),
- new List<Block>(new Block[] { action.Blocks[0] })));
- List<Block> newBlocks = new List<Block>();
- newBlocks.Add(newInitBlock);
- newBlocks.AddRange(action.Blocks);
- impl = new Implementation(Token.NoToken, proc.Name, node.TypeParameters, node.InParams, node.OutParams, action.LocVars, newBlocks);
- }
- else
- {
- Block newInitBlock = new Block(Token.NoToken, "_init", new List<Cmd>(), new ReturnCmd(Token.NoToken));
- List<Block> newBlocks = new List<Block>();
- newBlocks.Add(newInitBlock);
- impl = new Implementation(Token.NoToken, proc.Name, node.TypeParameters, node.InParams, node.OutParams, new List<Variable>(), newBlocks);
- }
- impl.Proc = proc;
- impl.Proc.AddAttribute("inline", new LiteralExpr(Token.NoToken, Microsoft.Basetypes.BigNum.FromInt(1)));
- impl.AddAttribute("inline", new LiteralExpr(Token.NoToken, Microsoft.Basetypes.BigNum.FromInt(1)));
- impls.Add(impl);
- }
- else
- {
- yieldingProcs.Add(proc);
- proc.Requires = this.VisitRequiresSeq(node.Requires);
- proc.Ensures = this.VisitEnsuresSeq(node.Ensures);
- }
- procMap[node] = proc;
- proc.Modifies = new List<IdentifierExpr>();
- moverTypeChecker.SharedVariables.Iter(x => proc.Modifies.Add(Expr.Ident(x)));
- }
- return procMap[node];
- }
-
- private Variable dummyLocalVar;
- public override Implementation VisitImplementation(Implementation node)
- {
- enclosingImpl = node;
- dummyLocalVar = new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken, "og_dummy", Type.Bool));
- Implementation impl = base.VisitImplementation(node);
- implMap[impl] = node;
- impl.LocVars.Add(dummyLocalVar);
- impl.Name = impl.Proc.Name;
- return impl;
- }
-
- public override Requires VisitRequires(Requires node)
- {
- Requires requires = base.VisitRequires(node);
- if (node.Free)
- return requires;
- if (!moverTypeChecker.absyToLayerNums[node].Contains(layerNum))
- requires.Condition = Expr.True;
- return requires;
- }
-
- public override Ensures VisitEnsures(Ensures node)
- {
- Ensures ensures = base.VisitEnsures(node);
- if (node.Free)
- return ensures;
- AtomicActionInfo atomicActionInfo = moverTypeChecker.procToActionInfo[enclosingProc] as AtomicActionInfo;
- bool isAtomicSpecification = atomicActionInfo != null && atomicActionInfo.ensures == node;
- if (isAtomicSpecification || !moverTypeChecker.absyToLayerNums[node].Contains(layerNum))
- {
- ensures.Condition = Expr.True;
- ensures.Attributes = OwickiGries.RemoveMoverAttribute(ensures.Attributes);
- }
- return ensures;
- }
-
- public override Cmd VisitAssertCmd(AssertCmd node)
- {
- AssertCmd assertCmd = (AssertCmd) base.VisitAssertCmd(node);
- if (!moverTypeChecker.absyToLayerNums[node].Contains(layerNum))
- assertCmd.Expr = Expr.True;
- return assertCmd;
- }
- }
-
- public class OwickiGries
- {
- LinearTypeChecker linearTypeChecker;
- MoverTypeChecker moverTypeChecker;
- Dictionary<Absy, Absy> absyMap;
- Dictionary<Implementation, Implementation> implMap;
- HashSet<Procedure> yieldingProcs;
- int layerNum;
- List<IdentifierExpr> globalMods;
- Dictionary<string, Procedure> asyncAndParallelCallDesugarings;
- List<Procedure> yieldCheckerProcs;
- List<Implementation> yieldCheckerImpls;
- Procedure yieldProc;
-
- Variable pc;
- Variable ok;
- Expr alpha;
- Expr beta;
- HashSet<Variable> frame;
-
- public OwickiGries(LinearTypeChecker linearTypeChecker, MoverTypeChecker moverTypeChecker, MyDuplicator duplicator)
- {
- this.linearTypeChecker = linearTypeChecker;
- this.moverTypeChecker = moverTypeChecker;
- this.absyMap = duplicator.absyMap;
- this.layerNum = duplicator.layerNum;
- this.implMap = duplicator.implMap;
- this.yieldingProcs = duplicator.yieldingProcs;
- Program program = linearTypeChecker.program;
- globalMods = new List<IdentifierExpr>();
- foreach (Variable g in moverTypeChecker.SharedVariables)
- {
- globalMods.Add(Expr.Ident(g));
- }
- asyncAndParallelCallDesugarings = new Dictionary<string, Procedure>();
- yieldCheckerProcs = new List<Procedure>();
- yieldCheckerImpls = new List<Implementation>();
- yieldProc = null;
- }
-
- private IEnumerable<Variable> AvailableLinearVars(Absy absy)
- {
- return linearTypeChecker.AvailableLinearVars(absyMap[absy]);
- }
-
- private CallCmd CallToYieldProc(IToken tok, Dictionary<Variable, Variable> ogOldGlobalMap, Dictionary<string, Variable> domainNameToLocalVar)
- {
- List<Expr> exprSeq = new List<Expr>();
- foreach (string domainName in linearTypeChecker.linearDomains.Keys)
- {
- exprSeq.Add(Expr.Ident(domainNameToLocalVar[domainName]));
- }
- foreach (IdentifierExpr ie in globalMods)
- {
- exprSeq.Add(Expr.Ident(ogOldGlobalMap[ie.Decl]));
- }
- if (yieldProc == null)
- {
- List<Variable> inputs = new List<Variable>();
- foreach (string domainName in linearTypeChecker.linearDomains.Keys)
- {
- var domain = linearTypeChecker.linearDomains[domainName];
- Formal f = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "linear_" + domainName + "_in", new MapType(Token.NoToken, new List<TypeVariable>(), new List<Type> { domain.elementType }, Type.Bool)), true);
- inputs.Add(f);
- }
- foreach (IdentifierExpr ie in globalMods)
- {
- Formal f = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, string.Format("og_global_old_{0}", ie.Decl.Name), ie.Decl.TypedIdent.Type), true);
- inputs.Add(f);
- }
- yieldProc = new Procedure(Token.NoToken, string.Format("og_yield_{0}", layerNum), new List<TypeVariable>(), inputs, new List<Variable>(), new List<Requires>(), new List<IdentifierExpr>(), new List<Ensures>());
- yieldProc.AddAttribute("inline", new LiteralExpr(Token.NoToken, Microsoft.Basetypes.BigNum.FromInt(1)));
- }
- CallCmd yieldCallCmd = new CallCmd(Token.NoToken, yieldProc.Name, exprSeq, new List<IdentifierExpr>());
- yieldCallCmd.Proc = yieldProc;
- return yieldCallCmd;
- }
-
- private void AddCallToYieldProc(IToken tok, List<Cmd> newCmds, Dictionary<Variable, Variable> ogOldGlobalMap, Dictionary<string, Variable> domainNameToLocalVar)
- {
- if (!CommandLineOptions.Clo.TrustNonInterference)
- {
- CallCmd yieldCallCmd = CallToYieldProc(tok, ogOldGlobalMap, domainNameToLocalVar);
- newCmds.Add(yieldCallCmd);
- }
-
- if (pc != null)
- {
- Expr aa = OldEqualityExprForGlobals(ogOldGlobalMap);
- Expr bb = OldEqualityExpr(ogOldGlobalMap);
-
- // assert pc || g_old == g || beta(i, g_old, o, g);
- Expr assertExpr = Expr.Or(Expr.Ident(pc), Expr.Or(aa, beta));
- assertExpr.Typecheck(new TypecheckingContext(null));
- AssertCmd skipOrBetaAssertCmd = new AssertCmd(tok, assertExpr);
- skipOrBetaAssertCmd.ErrorData = "Transition invariant in initial state violated";
- newCmds.Add(skipOrBetaAssertCmd);
-
- // assert pc ==> o_old == o && g_old == g;
- assertExpr = Expr.Imp(Expr.Ident(pc), bb);
- assertExpr.Typecheck(new TypecheckingContext(null));
- AssertCmd skipAssertCmd = new AssertCmd(tok, assertExpr);
- skipAssertCmd.ErrorData = "Transition invariant in final state violated"; ;
- newCmds.Add(skipAssertCmd);
-
- // pc, ok := g_old == g ==> pc, ok || beta(i, g_old, o, g);
- List<AssignLhs> pcUpdateLHS = new List<AssignLhs>(
- new AssignLhs[] {
- new SimpleAssignLhs(Token.NoToken, Expr.Ident(pc)),
- new SimpleAssignLhs(Token.NoToken, Expr.Ident(ok))
- });
- List<Expr> pcUpdateRHS = new List<Expr>(
- new Expr[] {
- Expr.Imp(aa, Expr.Ident(pc)),
- Expr.Or(Expr.Ident(ok), beta)
- });
- foreach (Expr e in pcUpdateRHS)
- {
- e.Typecheck(new TypecheckingContext(null));
- }
- newCmds.Add(new AssignCmd(Token.NoToken, pcUpdateLHS, pcUpdateRHS));
- }
- }
-
- private Dictionary<string, Expr> ComputeAvailableExprs(IEnumerable<Variable> availableLinearVars, Dictionary<string, Variable> domainNameToInputVar)
- {
- Dictionary<string, Expr> domainNameToExpr = new Dictionary<string, Expr>();
- foreach (var domainName in linearTypeChecker.linearDomains.Keys)
- {
- var expr = Expr.Ident(domainNameToInputVar[domainName]);
- expr.Resolve(new ResolutionContext(null));
- expr.Typecheck(new TypecheckingContext(null));
- domainNameToExpr[domainName] = expr;
- }
- foreach (Variable v in availableLinearVars)
- {
- var domainName = linearTypeChecker.FindDomainName(v);
- if (!linearTypeChecker.linearDomains.ContainsKey(domainName)) continue;
- var domain = linearTypeChecker.linearDomains[domainName];
- if (!domain.collectors.ContainsKey(v.TypedIdent.Type)) continue;
- Expr ie = new NAryExpr(Token.NoToken, new FunctionCall(domain.collectors[v.TypedIdent.Type]), new List<Expr> { Expr.Ident(v) });
- var expr = new NAryExpr(Token.NoToken, new FunctionCall(domain.mapOrBool), new List<Expr> { ie, domainNameToExpr[domainName] });
- expr.Resolve(new ResolutionContext(null));
- expr.Typecheck(new TypecheckingContext(null));
- domainNameToExpr[domainName] = expr;
- }
- return domainNameToExpr;
- }
-
- private void AddUpdatesToOldGlobalVars(List<Cmd> newCmds, Dictionary<Variable, Variable> ogOldGlobalMap, Dictionary<string, Variable> domainNameToLocalVar, Dictionary<string, Expr> domainNameToExpr)
- {
- List<AssignLhs> lhss = new List<AssignLhs>();
- List<Expr> rhss = new List<Expr>();
- foreach (var domainName in linearTypeChecker.linearDomains.Keys)
- {
- lhss.Add(new SimpleAssignLhs(Token.NoToken, Expr.Ident(domainNameToLocalVar[domainName])));
- rhss.Add(domainNameToExpr[domainName]);
- }
- foreach (Variable g in ogOldGlobalMap.Keys)
- {
- lhss.Add(new SimpleAssignLhs(Token.NoToken, Expr.Ident(ogOldGlobalMap[g])));
- rhss.Add(Expr.Ident(g));
- }
- if (lhss.Count > 0)
- {
- newCmds.Add(new AssignCmd(Token.NoToken, lhss, rhss));
- }
- }
-
- private Expr OldEqualityExpr(Dictionary<Variable, Variable> ogOldGlobalMap)
- {
- Expr bb = Expr.True;
- foreach (Variable o in ogOldGlobalMap.Keys)
- {
- if (o is GlobalVariable && !frame.Contains(o)) continue;
- bb = Expr.And(bb, Expr.Eq(Expr.Ident(o), Expr.Ident(ogOldGlobalMap[o])));
- bb.Type = Type.Bool;
- }
- return bb;
- }
-
- private Expr OldEqualityExprForGlobals(Dictionary<Variable, Variable> ogOldGlobalMap)
- {
- Expr bb = Expr.True;
- foreach (Variable o in ogOldGlobalMap.Keys)
- {
- if (o is GlobalVariable && frame.Contains(o))
- {
- bb = Expr.And(bb, Expr.Eq(Expr.Ident(o), Expr.Ident(ogOldGlobalMap[o])));
- bb.Type = Type.Bool;
- }
- }
- return bb;
- }
-
- private void DesugarYield(YieldCmd yieldCmd, List<Cmd> cmds, List<Cmd> newCmds, Dictionary<Variable, Variable> ogOldGlobalMap, Dictionary<string, Variable> domainNameToInputVar, Dictionary<string, Variable> domainNameToLocalVar)
- {
- AddCallToYieldProc(yieldCmd.tok, newCmds, ogOldGlobalMap, domainNameToLocalVar);
-
- if (globalMods.Count > 0)
- {
- newCmds.Add(new HavocCmd(Token.NoToken, globalMods));
- if (pc != null)
- {
- // assume pc || alpha(i, g);
- Expr assumeExpr = Expr.Or(Expr.Ident(pc), alpha);
- assumeExpr.Type = Type.Bool;
- newCmds.Add(new AssumeCmd(Token.NoToken, assumeExpr));
- }
- }
-
- Dictionary<string, Expr> domainNameToExpr = ComputeAvailableExprs(AvailableLinearVars(yieldCmd), domainNameToInputVar);
- AddUpdatesToOldGlobalVars(newCmds, ogOldGlobalMap, domainNameToLocalVar, domainNameToExpr);
-
- for (int j = 0; j < cmds.Count; j++)
- {
- PredicateCmd predCmd = (PredicateCmd)cmds[j];
- newCmds.Add(new AssumeCmd(Token.NoToken, predCmd.Expr));
- }
- }
-
- public void DesugarParallelCallCmd(List<Cmd> newCmds, ParCallCmd parCallCmd)
- {
- List<string> parallelCalleeNames = new List<string>();
- List<Expr> ins = new List<Expr>();
- List<IdentifierExpr> outs = new List<IdentifierExpr>();
- string procName = "og";
- foreach (CallCmd callCmd in parCallCmd.CallCmds)
- {
- procName = procName + "_" + callCmd.Proc.Name;
- ins.AddRange(callCmd.Ins);
- outs.AddRange(callCmd.Outs);
- }
- Procedure proc;
- if (asyncAndParallelCallDesugarings.ContainsKey(procName))
- {
- proc = asyncAndParallelCallDesugarings[procName];
- }
- else
- {
- List<Variable> inParams = new List<Variable>();
- List<Variable> outParams = new List<Variable>();
- List<Requires> requiresSeq = new List<Requires>();
- List<Ensures> ensuresSeq = new List<Ensures>();
- int count = 0;
- foreach (CallCmd callCmd in parCallCmd.CallCmds)
- {
- Dictionary<Variable, Expr> map = new Dictionary<Variable, Expr>();
- foreach (Variable x in callCmd.Proc.InParams)
- {
- Variable y = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, string.Format("og_{0}_{1}", count, x.Name), x.TypedIdent.Type), true);
- inParams.Add(y);
- map[x] = Expr.Ident(y);
- }
- foreach (Variable x in callCmd.Proc.OutParams)
- {
- Variable y = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, string.Format("og_{0}_{1}", count, x.Name), x.TypedIdent.Type), false);
- outParams.Add(y);
- map[x] = Expr.Ident(y);
- }
- Contract.Assume(callCmd.Proc.TypeParameters.Count == 0);
- Substitution subst = Substituter.SubstitutionFromHashtable(map);
- foreach (Requires req in callCmd.Proc.Requires)
- {
- requiresSeq.Add(new Requires(req.tok, req.Free, Substituter.Apply(subst, req.Condition), null, req.Attributes));
- }
- foreach (Ensures ens in callCmd.Proc.Ensures)
- {
- ensuresSeq.Add(new Ensures(ens.tok, ens.Free, Substituter.Apply(subst, ens.Condition), null, ens.Attributes));
- }
- count++;
- }
- proc = new Procedure(Token.NoToken, procName, new List<TypeVariable>(), inParams, outParams, requiresSeq, globalMods, ensuresSeq);
- asyncAndParallelCallDesugarings[procName] = proc;
- }
- CallCmd dummyCallCmd = new CallCmd(parCallCmd.tok, proc.Name, ins, outs, parCallCmd.Attributes);
- dummyCallCmd.Proc = proc;
- newCmds.Add(dummyCallCmd);
- }
-
- private void CreateYieldCheckerImpl(Implementation impl, List<List<Cmd>> yields)
- {
- if (yields.Count == 0) return;
-
- Dictionary<Variable, Expr> map = new Dictionary<Variable, Expr>();
- foreach (Variable local in impl.LocVars)
- {
- var copy = new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken, local.Name, local.TypedIdent.Type));
- map[local] = Expr.Ident(copy);
- }
-
- Program program = linearTypeChecker.program;
- List<Variable> locals = new List<Variable>();
- List<Variable> inputs = new List<Variable>();
- foreach (IdentifierExpr ie in map.Values)
- {
- locals.Add(ie.Decl);
- }
- for (int i = 0; i < impl.InParams.Count - linearTypeChecker.linearDomains.Count; i++)
- {
- Variable inParam = impl.InParams[i];
- Variable copy = new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken, inParam.Name, inParam.TypedIdent.Type));
- locals.Add(copy);
- map[impl.InParams[i]] = Expr.Ident(copy);
- }
- {
- int i = impl.InParams.Count - linearTypeChecker.linearDomains.Count;
- foreach (string domainName in linearTypeChecker.linearDomains.Keys)
- {
- Variable inParam = impl.InParams[i];
- Variable copy = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, inParam.Name, inParam.TypedIdent.Type), true);
- inputs.Add(copy);
- map[impl.InParams[i]] = Expr.Ident(copy);
- i++;
- }
- }
- for (int i = 0; i < impl.OutParams.Count; i++)
- {
- Variable outParam = impl.OutParams[i];
- var copy = new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken, outParam.Name, outParam.TypedIdent.Type));
- locals.Add(copy);
- map[impl.OutParams[i]] = Expr.Ident(copy);
- }
- Dictionary<Variable, Expr> ogOldLocalMap = new Dictionary<Variable, Expr>();
- Dictionary<Variable, Expr> assumeMap = new Dictionary<Variable, Expr>(map);
- foreach (IdentifierExpr ie in globalMods)
- {
- Variable g = ie.Decl;
- var copy = new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken, string.Format("og_local_old_{0}", g.Name), g.TypedIdent.Type));
- locals.Add(copy);
- ogOldLocalMap[g] = Expr.Ident(copy);
- Formal f = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, string.Format("og_global_old_{0}", g.Name), g.TypedIdent.Type), true);
- inputs.Add(f);
- assumeMap[g] = Expr.Ident(f);
- }
-
- Substitution assumeSubst = Substituter.SubstitutionFromHashtable(assumeMap);
- Substitution oldSubst = Substituter.SubstitutionFromHashtable(ogOldLocalMap);
- Substitution subst = Substituter.SubstitutionFromHashtable(map);
- List<Block> yieldCheckerBlocks = new List<Block>();
- List<String> labels = new List<String>();
- List<Block> labelTargets = new List<Block>();
- Block yieldCheckerBlock = new Block(Token.NoToken, "exit", new List<Cmd>(), new ReturnCmd(Token.NoToken));
- labels.Add(yieldCheckerBlock.Label);
- labelTargets.Add(yieldCheckerBlock);
- yieldCheckerBlocks.Add(yieldCheckerBlock);
- int yieldCount = 0;
- foreach (List<Cmd> cs in yields)
- {
- List<Cmd> newCmds = new List<Cmd>();
- foreach (Cmd cmd in cs)
- {
- PredicateCmd predCmd = (PredicateCmd)cmd;
- newCmds.Add(new AssumeCmd(Token.NoToken, Substituter.ApplyReplacingOldExprs(assumeSubst, oldSubst, predCmd.Expr)));
- }
- foreach (Cmd cmd in cs)
- {
- PredicateCmd predCmd = (PredicateCmd)cmd;
- var newExpr = Substituter.ApplyReplacingOldExprs(subst, oldSubst, predCmd.Expr);
- if (predCmd is AssertCmd)
- {
- AssertCmd assertCmd = new AssertCmd(predCmd.tok, newExpr, predCmd.Attributes);
- assertCmd.ErrorData = "Non-interference check failed";
- newCmds.Add(assertCmd);
- }
- else
- {
- newCmds.Add(new AssumeCmd(Token.NoToken, newExpr));
- }
- }
- newCmds.Add(new AssumeCmd(Token.NoToken, Expr.False));
- yieldCheckerBlock = new Block(Token.NoToken, "L" + yieldCount++, newCmds, new ReturnCmd(Token.NoToken));
- labels.Add(yieldCheckerBlock.Label);
- labelTargets.Add(yieldCheckerBlock);
- yieldCheckerBlocks.Add(yieldCheckerBlock);
- }
- yieldCheckerBlocks.Insert(0, new Block(Token.NoToken, "enter", new List<Cmd>(), new GotoCmd(Token.NoToken, labels, labelTargets)));
-
- // Create the yield checker procedure
- var yieldCheckerName = string.Format("{0}_YieldChecker_{1}", "Impl", impl.Name);
- var yieldCheckerProc = new Procedure(Token.NoToken, yieldCheckerName, impl.TypeParameters, inputs, new List<Variable>(), new List<Requires>(), new List<IdentifierExpr>(), new List<Ensures>());
- yieldCheckerProc.AddAttribute("inline", new LiteralExpr(Token.NoToken, Microsoft.Basetypes.BigNum.FromInt(1)));
- yieldCheckerProcs.Add(yieldCheckerProc);
-
- // Create the yield checker implementation
- var yieldCheckerImpl = new Implementation(Token.NoToken, yieldCheckerName, impl.TypeParameters, inputs, new List<Variable>(), locals, yieldCheckerBlocks);
- yieldCheckerImpl.Proc = yieldCheckerProc;
- yieldCheckerImpl.AddAttribute("inline", new LiteralExpr(Token.NoToken, Microsoft.Basetypes.BigNum.FromInt(1)));
- yieldCheckerImpls.Add(yieldCheckerImpl);
- }
-
- private bool IsYieldingHeader(Graph<Block> graph, Block header)
- {
- foreach (Block backEdgeNode in graph.BackEdgeNodes(header))
- {
- foreach (Block x in graph.NaturalLoops(header, backEdgeNode))
- {
- foreach (Cmd cmd in x.Cmds)
- {
- if (cmd is YieldCmd)
- return true;
- if (cmd is ParCallCmd)
- return true;
- CallCmd callCmd = cmd as CallCmd;
- if (callCmd == null) continue;
- if (yieldingProcs.Contains(callCmd.Proc))
- return true;
- }
- }
- }
- return false;
- }
-
- private Graph<Block> ComputeYieldingLoopHeaders(Implementation impl, out HashSet<Block> yieldingHeaders)
- {
- Graph<Block> graph;
- impl.PruneUnreachableBlocks();
- impl.ComputePredecessorsForBlocks();
- graph = Program.GraphFromImpl(impl);
- graph.ComputeLoops();
- if (!graph.Reducible)
- {
- throw new Exception("Irreducible flow graphs are unsupported.");
- }
- yieldingHeaders = new HashSet<Block>();
- IEnumerable<Block> sortedHeaders = graph.SortHeadersByDominance();
- foreach (Block header in sortedHeaders)
- {
- if (yieldingHeaders.Any(x => graph.DominatorMap.DominatedBy(x, header)))
- {
- yieldingHeaders.Add(header);
- }
- else if (IsYieldingHeader(graph, header))
- {
- yieldingHeaders.Add(header);
- }
- else
- {
- continue;
- }
- }
- return graph;
- }
-
- private void SetupRefinementCheck(Implementation impl,
- out List<Variable> newLocalVars,
- out Dictionary<string, Variable> domainNameToInputVar, out Dictionary<string, Variable> domainNameToLocalVar, out Dictionary<Variable, Variable> ogOldGlobalMap)
- {
- pc = null;
- ok = null;
- alpha = null;
- beta = null;
- frame = null;
-
- newLocalVars = new List<Variable>();
- Program program = linearTypeChecker.program;
- ogOldGlobalMap = new Dictionary<Variable, Variable>();
- foreach (IdentifierExpr ie in globalMods)
- {
- Variable g = ie.Decl;
- LocalVariable l = new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken, string.Format("og_global_old_{0}", g.Name), g.TypedIdent.Type));
- ogOldGlobalMap[g] = l;
- newLocalVars.Add(l);
- }
-
- Procedure originalProc = implMap[impl].Proc;
- ActionInfo actionInfo = moverTypeChecker.procToActionInfo[originalProc];
- if (actionInfo.createdAtLayerNum == this.layerNum)
- {
- pc = new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken, "og_pc", Type.Bool));
- newLocalVars.Add(pc);
- ok = new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken, "og_ok", Type.Bool));
- newLocalVars.Add(ok);
- Dictionary<Variable, Expr> alwaysMap = new Dictionary<Variable, Expr>();
- for (int i = 0; i < originalProc.InParams.Count; i++)
- {
- alwaysMap[originalProc.InParams[i]] = Expr.Ident(impl.InParams[i]);
- }
- for (int i = 0; i < originalProc.OutParams.Count; i++)
- {
- alwaysMap[originalProc.OutParams[i]] = Expr.Ident(impl.OutParams[i]);
- }
- Substitution always = Substituter.SubstitutionFromHashtable(alwaysMap);
- Dictionary<Variable, Expr> foroldMap = new Dictionary<Variable, Expr>();
- foreach (IdentifierExpr ie in globalMods)
- {
- foroldMap[ie.Decl] = Expr.Ident(ogOldGlobalMap[ie.Decl]);
- }
- Substitution forold = Substituter.SubstitutionFromHashtable(foroldMap);
- frame = new HashSet<Variable>(moverTypeChecker.SharedVariables);
- HashSet<Variable> introducedVars = new HashSet<Variable>();
- foreach (Variable v in moverTypeChecker.SharedVariables)
- {
- if (moverTypeChecker.globalVarToSharedVarInfo[v].hideLayerNum <= actionInfo.createdAtLayerNum ||
- moverTypeChecker.globalVarToSharedVarInfo[v].introLayerNum > actionInfo.createdAtLayerNum)
- {
- frame.Remove(v);
- }
- if (moverTypeChecker.globalVarToSharedVarInfo[v].introLayerNum == actionInfo.createdAtLayerNum)
- {
- introducedVars.Add(v);
- }
- }
- AtomicActionInfo atomicActionInfo = actionInfo as AtomicActionInfo;
- if (atomicActionInfo == null)
- {
- beta = Expr.True;
- foreach (var v in frame)
- {
- beta = Expr.And(beta, Expr.Eq(Expr.Ident(v), foroldMap[v]));
- }
- alpha = Expr.True;
- }
- else
- {
- Expr betaExpr = (new MoverCheck.TransitionRelationComputation(moverTypeChecker.program, atomicActionInfo, frame, introducedVars)).TransitionRelationCompute();
- beta = Substituter.ApplyReplacingOldExprs(always, forold, betaExpr);
- Expr alphaExpr = Expr.True;
- foreach (AssertCmd assertCmd in atomicActionInfo.thisGate)
- {
- alphaExpr = Expr.And(alphaExpr, assertCmd.Expr);
- alphaExpr.Type = Type.Bool;
- }
- alpha = Substituter.Apply(always, alphaExpr);
- }
- foreach (Variable f in impl.OutParams)
- {
- LocalVariable copy = new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken, string.Format("og_old_{0}", f.Name), f.TypedIdent.Type));
- newLocalVars.Add(copy);
- ogOldGlobalMap[f] = copy;
- }
- }
-
- domainNameToInputVar = new Dictionary<string, Variable>();
- domainNameToLocalVar = new Dictionary<string, Variable>();
- {
- int i = impl.InParams.Count - linearTypeChecker.linearDomains.Count;
- foreach (string domainName in linearTypeChecker.linearDomains.Keys)
- {
- Variable inParam = impl.InParams[i];
- domainNameToInputVar[domainName] = inParam;
- Variable l = new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken, inParam.Name + "_local", inParam.TypedIdent.Type));
- domainNameToLocalVar[domainName] = l;
- newLocalVars.Add(l);
- i++;
- }
- }
- }
-
- private void TransformImpl(Implementation impl)
- {
- HashSet<Block> yieldingHeaders;
- Graph<Block> graph = ComputeYieldingLoopHeaders(impl, out yieldingHeaders);
-
- List<Variable> newLocalVars;
- Dictionary<string, Variable> domainNameToInputVar, domainNameToLocalVar;
- Dictionary<Variable, Variable> ogOldGlobalMap;
- SetupRefinementCheck(impl, out newLocalVars, out domainNameToInputVar, out domainNameToLocalVar, out ogOldGlobalMap);
-
- List<List<Cmd>> yields = CollectAndDesugarYields(impl, domainNameToInputVar, domainNameToLocalVar, ogOldGlobalMap);
-
- List<Variable> oldPcs, oldOks;
- ProcessLoopHeaders(impl, graph, yieldingHeaders, domainNameToInputVar, domainNameToLocalVar, ogOldGlobalMap, out oldPcs, out oldOks);
-
- AddInitialBlock(impl, oldPcs, oldOks, domainNameToInputVar, domainNameToLocalVar, ogOldGlobalMap);
-
- CreateYieldCheckerImpl(impl, yields);
-
- impl.LocVars.AddRange(newLocalVars);
- impl.LocVars.AddRange(oldPcs);
- impl.LocVars.AddRange(oldOks);
-
- UnifyCallsToYieldProc(impl, ogOldGlobalMap, domainNameToLocalVar);
- }
-
- private void UnifyCallsToYieldProc(Implementation impl, Dictionary<Variable, Variable> ogOldGlobalMap, Dictionary<string, Variable> domainNameToLocalVar)
- {
- CallCmd yieldCallCmd = CallToYieldProc(Token.NoToken, ogOldGlobalMap, domainNameToLocalVar);
- Block yieldCheckBlock = new Block(Token.NoToken, "CallToYieldProc", new List<Cmd>(new Cmd[] { yieldCallCmd, new AssumeCmd(Token.NoToken, Expr.False) }), new ReturnCmd(Token.NoToken));
- List<Block> newBlocks = new List<Block>();
- foreach (Block b in impl.Blocks)
- {
- TransferCmd transferCmd = b.TransferCmd;
- List<Cmd> newCmds = new List<Cmd>();
- for (int i = b.Cmds.Count-1; i >= 0; i--)
- {
- CallCmd callCmd = b.Cmds[i] as CallCmd;
- if (callCmd == null || callCmd.Proc != yieldProc)
- {
- newCmds.Insert(0, b.Cmds[i]);
- }
- else
- {
- Block newBlock = new Block(Token.NoToken, b.Label + i, newCmds, transferCmd);
- newCmds = new List<Cmd>();
- transferCmd = new GotoCmd(Token.NoToken, new List<string>(new string[] { newBlock.Label, yieldCheckBlock.Label }),
- new List<Block>(new Block[] { newBlock, yieldCheckBlock }));
- newBlocks.Add(newBlock);
- }
- }
- b.Cmds = newCmds;
- b.TransferCmd = transferCmd;
- }
- impl.Blocks.AddRange(newBlocks);
- impl.Blocks.Add(yieldCheckBlock);
- }
-
- private List<List<Cmd>> CollectAndDesugarYields(Implementation impl,
- Dictionary<string, Variable> domainNameToInputVar, Dictionary<string, Variable> domainNameToLocalVar, Dictionary<Variable, Variable> ogOldGlobalMap)
- {
- // Collect the yield predicates and desugar yields
- List<List<Cmd>> yields = new List<List<Cmd>>();
- List<Cmd> cmds = new List<Cmd>();
- foreach (Block b in impl.Blocks)
- {
- YieldCmd yieldCmd = null;
- List<Cmd> newCmds = new List<Cmd>();
- for (int i = 0; i < b.Cmds.Count; i++)
- {
- Cmd cmd = b.Cmds[i];
- if (cmd is YieldCmd)
- {
- yieldCmd = (YieldCmd)cmd;
- continue;
- }
- if (yieldCmd != null)
- {
- PredicateCmd pcmd = cmd as PredicateCmd;
- if (pcmd == null)
- {
- DesugarYield(yieldCmd, cmds, newCmds, ogOldGlobalMap, domainNameToInputVar, domainNameToLocalVar);
- if (cmds.Count > 0)
- {
- yields.Add(cmds);
- cmds = new List<Cmd>();
- }
- yieldCmd = null;
- }
- else
- {
- cmds.Add(pcmd);
- }
- }
-
- if (cmd is CallCmd)
- {
- CallCmd callCmd = cmd as CallCmd;
- if (yieldingProcs.Contains(callCmd.Proc))
- {
- AddCallToYieldProc(callCmd.tok, newCmds, ogOldGlobalMap, domainNameToLocalVar);
- }
- if (callCmd.IsAsync)
- {
- if (!asyncAndParallelCallDesugarings.ContainsKey(callCmd.Proc.Name))
- {
- asyncAndParallelCallDesugarings[callCmd.Proc.Name] = new Procedure(Token.NoToken, string.Format("DummyAsyncTarget_{0}", callCmd.Proc.Name), callCmd.Proc.TypeParameters, callCmd.Proc.InParams, callCmd.Proc.OutParams, callCmd.Proc.Requires, new List<IdentifierExpr>(), new List<Ensures>());
- }
- var dummyAsyncTargetProc = asyncAndParallelCallDesugarings[callCmd.Proc.Name];
- CallCmd dummyCallCmd = new CallCmd(callCmd.tok, dummyAsyncTargetProc.Name, callCmd.Ins, callCmd.Outs, callCmd.Attributes);
- dummyCallCmd.Proc = dummyAsyncTargetProc;
- newCmds.Add(dummyCallCmd);
- }
- else
- {
- newCmds.Add(callCmd);
- }
- if (yieldingProcs.Contains(callCmd.Proc))
- {
- HashSet<Variable> availableLinearVars = new HashSet<Variable>(AvailableLinearVars(callCmd));
- linearTypeChecker.AddAvailableVars(callCmd, availableLinearVars);
- Dictionary<string, Expr> domainNameToExpr = ComputeAvailableExprs(availableLinearVars, domainNameToInputVar);
- AddUpdatesToOldGlobalVars(newCmds, ogOldGlobalMap, domainNameToLocalVar, domainNameToExpr);
- }
- }
- else if (cmd is ParCallCmd)
- {
- ParCallCmd parCallCmd = cmd as ParCallCmd;
- AddCallToYieldProc(parCallCmd.tok, newCmds, ogOldGlobalMap, domainNameToLocalVar);
- DesugarParallelCallCmd(newCmds, parCallCmd);
- HashSet<Variable> availableLinearVars = new HashSet<Variable>(AvailableLinearVars(parCallCmd));
- linearTypeChecker.AddAvailableVars(parCallCmd, availableLinearVars);
- Dictionary<string, Expr> domainNameToExpr = ComputeAvailableExprs(availableLinearVars, domainNameToInputVar);
- AddUpdatesToOldGlobalVars(newCmds, ogOldGlobalMap, domainNameToLocalVar, domainNameToExpr);
- }
- else
- {
- newCmds.Add(cmd);
- }
- }
- if (yieldCmd != null)
- {
- DesugarYield(yieldCmd, cmds, newCmds, ogOldGlobalMap, domainNameToInputVar, domainNameToLocalVar);
- if (cmds.Count > 0)
- {
- yields.Add(cmds);
- cmds = new List<Cmd>();
- }
- }
- if (b.TransferCmd is ReturnCmd)
- {
- AddCallToYieldProc(b.TransferCmd.tok, newCmds, ogOldGlobalMap, domainNameToLocalVar);
- if (pc != null)
- {
- AssertCmd assertCmd = new AssertCmd(b.TransferCmd.tok, Expr.Ident(ok));
- assertCmd.ErrorData = "Failed to execute atomic action before procedure return";
- newCmds.Add(assertCmd);
- }
- }
- b.Cmds = newCmds;
- }
- return yields;
- }
-
- private void ProcessLoopHeaders(Implementation impl, Graph<Block> graph, HashSet<Block> yieldingHeaders,
- Dictionary<string, Variable> domainNameToInputVar, Dictionary<string, Variable> domainNameToLocalVar, Dictionary<Variable, Variable> ogOldGlobalMap,
- out List<Variable> oldPcs, out List<Variable> oldOks)
- {
- oldPcs = new List<Variable>();
- oldOks = new List<Variable>();
- foreach (Block header in yieldingHeaders)
- {
- LocalVariable oldPc = null;
- LocalVariable oldOk = null;
- if (pc != null)
- {
- oldPc = new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken, string.Format("{0}_{1}", pc.Name, header.Label), Type.Bool));
- oldPcs.Add(oldPc);
- oldOk = new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken, string.Format("{0}_{1}", ok.Name, header.Label), Type.Bool));
- oldOks.Add(oldOk);
- }
- Dictionary<string, Expr> domainNameToExpr = ComputeAvailableExprs(AvailableLinearVars(header), domainNameToInputVar);
- foreach (Block pred in header.Predecessors)
- {
- AddCallToYieldProc(header.tok, pred.Cmds, ogOldGlobalMap, domainNameToLocalVar);
- if (pc != null && !graph.BackEdgeNodes(header).Contains(pred))
- {
- pred.Cmds.Add(new AssignCmd(Token.NoToken, new List<AssignLhs>(
- new AssignLhs[] { new SimpleAssignLhs(Token.NoToken, Expr.Ident(oldPc)), new SimpleAssignLhs(Token.NoToken, Expr.Ident(oldOk)) }),
- new List<Expr>(new Expr[] { Expr.Ident(pc), Expr.Ident(ok) })));
- }
- AddUpdatesToOldGlobalVars(pred.Cmds, ogOldGlobalMap, domainNameToLocalVar, domainNameToExpr);
- }
- List<Cmd> newCmds = new List<Cmd>();
- if (pc != null)
- {
- AssertCmd assertCmd;
- assertCmd = new AssertCmd(header.tok, Expr.Eq(Expr.Ident(oldPc), Expr.Ident(pc)));
- assertCmd.ErrorData = "Specification state must not change for transitions ending in loop headers";
- newCmds.Add(assertCmd);
- assertCmd = new AssertCmd(header.tok, Expr.Imp(Expr.Ident(oldOk), Expr.Ident(ok)));
- assertCmd.ErrorData = "Specification state must not change for transitions ending in loop headers";
- newCmds.Add(assertCmd);
- }
- foreach (string domainName in linearTypeChecker.linearDomains.Keys)
- {
- newCmds.Add(new AssumeCmd(Token.NoToken, Expr.Eq(Expr.Ident(domainNameToLocalVar[domainName]), domainNameToExpr[domainName])));
- }
- foreach (Variable v in ogOldGlobalMap.Keys)
- {
- newCmds.Add(new AssumeCmd(Token.NoToken, Expr.Eq(Expr.Ident(v), Expr.Ident(ogOldGlobalMap[v]))));
- }
- newCmds.AddRange(header.Cmds);
- header.Cmds = newCmds;
- }
- }
-
- private void AddInitialBlock(Implementation impl, List<Variable> oldPcs, List<Variable> oldOks,
- Dictionary<string, Variable> domainNameToInputVar, Dictionary<string, Variable> domainNameToLocalVar, Dictionary<Variable, Variable> ogOldGlobalMap)
- {
- // Add initial block
- List<AssignLhs> lhss = new List<AssignLhs>();
- List<Expr> rhss = new List<Expr>();
- if (pc != null)
- {
- lhss.Add(new SimpleAssignLhs(Token.NoToken, Expr.Ident(pc)));
- rhss.Add(Expr.False);
- foreach (Variable oldPc in oldPcs)
- {
- lhss.Add(new SimpleAssignLhs(Token.NoToken, Expr.Ident(oldPc)));
- rhss.Add(Expr.False);
- }
- lhss.Add(new SimpleAssignLhs(Token.NoToken, Expr.Ident(ok)));
- rhss.Add(Expr.False);
- foreach (Variable oldOk in oldOks)
- {
- lhss.Add(new SimpleAssignLhs(Token.NoToken, Expr.Ident(oldOk)));
- rhss.Add(Expr.False);
- }
- }
- Dictionary<string, Expr> domainNameToExpr = new Dictionary<string, Expr>();
- foreach (var domainName in linearTypeChecker.linearDomains.Keys)
- {
- domainNameToExpr[domainName] = Expr.Ident(domainNameToInputVar[domainName]);
- }
- for (int i = 0; i < impl.InParams.Count - linearTypeChecker.linearDomains.Count; i++)
- {
- Variable v = impl.InParams[i];
- var domainName = linearTypeChecker.FindDomainName(v);
- if (domainName == null) continue;
- if (!linearTypeChecker.linearDomains.ContainsKey(domainName)) continue;
- var domain = linearTypeChecker.linearDomains[domainName];
- if (!domain.collectors.ContainsKey(v.TypedIdent.Type)) continue;
- Expr ie = new NAryExpr(Token.NoToken, new FunctionCall(domain.collectors[v.TypedIdent.Type]), new List<Expr> { Expr.Ident(v) });
- domainNameToExpr[domainName] = new NAryExpr(Token.NoToken, new FunctionCall(domain.mapOrBool), new List<Expr> { ie, domainNameToExpr[domainName] });
- }
- foreach (string domainName in linearTypeChecker.linearDomains.Keys)
- {
- lhss.Add(new SimpleAssignLhs(Token.NoToken, Expr.Ident(domainNameToLocalVar[domainName])));
- rhss.Add(domainNameToExpr[domainName]);
- }
- foreach (Variable g in ogOldGlobalMap.Keys)
- {
- lhss.Add(new SimpleAssignLhs(Token.NoToken, Expr.Ident(ogOldGlobalMap[g])));
- rhss.Add(Expr.Ident(g));
- }
- if (lhss.Count > 0)
- {
- Block initBlock = new Block(Token.NoToken, "og_init", new List<Cmd> { new AssignCmd(Token.NoToken, lhss, rhss) }, new GotoCmd(Token.NoToken, new List<String> { impl.Blocks[0].Label }, new List<Block> { impl.Blocks[0] }));
- impl.Blocks.Insert(0, initBlock);
- }
- }
-
- private void AddYieldProcAndImpl(List<Declaration> decls)
- {
- if (yieldProc == null) return;
-
- Program program = linearTypeChecker.program;
- List<Variable> inputs = new List<Variable>();
- foreach (string domainName in linearTypeChecker.linearDomains.Keys)
- {
- var domain = linearTypeChecker.linearDomains[domainName];
- Formal f = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "linear_" + domainName + "_in", new MapType(Token.NoToken, new List<TypeVariable>(), new List<Type> { domain.elementType }, Type.Bool)), true);
- inputs.Add(f);
- }
- foreach (IdentifierExpr ie in globalMods)
- {
- Formal f = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, string.Format("og_global_old_{0}", ie.Decl.Name), ie.Decl.TypedIdent.Type), true);
- inputs.Add(f);
- }
- List<Block> blocks = new List<Block>();
- TransferCmd transferCmd = new ReturnCmd(Token.NoToken);
- if (yieldCheckerProcs.Count > 0)
- {
- List<Block> blockTargets = new List<Block>();
- List<String> labelTargets = new List<String>();
- int labelCount = 0;
- foreach (Procedure proc in yieldCheckerProcs)
- {
- List<Expr> exprSeq = new List<Expr>();
- foreach (Variable v in inputs)
- {
- exprSeq.Add(Expr.Ident(v));
- }
- CallCmd callCmd = new CallCmd(Token.NoToken, proc.Name, exprSeq, new List<IdentifierExpr>());
- callCmd.Proc = proc;
- string label = string.Format("L_{0}", labelCount++);
- Block block = new Block(Token.NoToken, label, new List<Cmd> { callCmd }, new ReturnCmd(Token.NoToken));
- labelTargets.Add(label);
- blockTargets.Add(block);
- blocks.Add(block);
- }
- transferCmd = new GotoCmd(Token.NoToken, labelTargets, blockTargets);
- }
- blocks.Insert(0, new Block(Token.NoToken, "enter", new List<Cmd>(), transferCmd));
-
- var yieldImpl = new Implementation(Token.NoToken, yieldProc.Name, new List<TypeVariable>(), inputs, new List<Variable>(), new List<Variable>(), blocks);
- yieldImpl.Proc = yieldProc;
- yieldImpl.AddAttribute("inline", new LiteralExpr(Token.NoToken, Microsoft.Basetypes.BigNum.FromInt(1)));
- decls.Add(yieldProc);
- decls.Add(yieldImpl);
- }
-
- public static QKeyValue RemoveYieldsAttribute(QKeyValue iter)
- {
- if (iter == null) return null;
- iter.Next = RemoveYieldsAttribute(iter.Next);
- return (iter.Key == "yields") ? iter.Next : iter;
- }
-
- public static QKeyValue RemoveMoverAttribute(QKeyValue iter)
- {
- if (iter == null) return null;
- iter.Next = RemoveMoverAttribute(iter.Next);
- if (iter.Key == "atomic" || iter.Key == "right" || iter.Key == "left" || iter.Key == "both")
- return iter.Next;
- else
- return iter;
- }
-
- private List<Declaration> Collect()
- {
- List<Declaration> decls = new List<Declaration>();
- foreach (Procedure proc in yieldCheckerProcs)
- {
- decls.Add(proc);
- }
- foreach (Implementation impl in yieldCheckerImpls)
- {
- decls.Add(impl);
- }
- foreach (Procedure proc in asyncAndParallelCallDesugarings.Values)
- {
- decls.Add(proc);
- }
- AddYieldProcAndImpl(decls);
- return decls;
- }
-
- public static void AddCheckers(LinearTypeChecker linearTypeChecker, MoverTypeChecker moverTypeChecker, List<Declaration> decls)
- {
- Program program = linearTypeChecker.program;
- foreach (int layerNum in moverTypeChecker.AllCreatedLayerNums.Except(new int[] { moverTypeChecker.leastUnimplementedLayerNum }))
- {
- if (CommandLineOptions.Clo.TrustLayersDownto <= layerNum || layerNum <= CommandLineOptions.Clo.TrustLayersUpto) continue;
-
- MyDuplicator duplicator = new MyDuplicator(moverTypeChecker, layerNum);
- foreach (var proc in program.Procedures)
- {
- if (!moverTypeChecker.procToActionInfo.ContainsKey(proc)) continue;
- Procedure duplicateProc = duplicator.VisitProcedure(proc);
- decls.Add(duplicateProc);
- }
- decls.AddRange(duplicator.impls);
- OwickiGries ogTransform = new OwickiGries(linearTypeChecker, moverTypeChecker, duplicator);
- foreach (var impl in program.Implementations)
- {
- if (!moverTypeChecker.procToActionInfo.ContainsKey(impl.Proc) || moverTypeChecker.procToActionInfo[impl.Proc].createdAtLayerNum < layerNum)
- continue;
- Implementation duplicateImpl = duplicator.VisitImplementation(impl);
- ogTransform.TransformImpl(duplicateImpl);
- decls.Add(duplicateImpl);
- }
- decls.AddRange(ogTransform.Collect());
- }
- }
- }
-}
+using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.Boogie; +using System.Diagnostics; +using System.Diagnostics.Contracts; +using Microsoft.Boogie.GraphUtil; + +namespace Microsoft.Boogie +{ + public class MyDuplicator : Duplicator + { + CivlTypeChecker civlTypeChecker; + public int layerNum; + Procedure enclosingProc; + Implementation enclosingImpl; + public Dictionary<Procedure, Procedure> procMap; /* Original -> Duplicate */ + public Dictionary<Absy, Absy> absyMap; /* Duplicate -> Original */ + public Dictionary<Implementation, Implementation> implMap; /* Duplicate -> Original */ + public HashSet<Procedure> yieldingProcs; + public List<Implementation> impls; + + public MyDuplicator(CivlTypeChecker civlTypeChecker, int layerNum) + { + this.civlTypeChecker = civlTypeChecker; + this.layerNum = layerNum; + this.enclosingProc = null; + this.enclosingImpl = null; + this.procMap = new Dictionary<Procedure, Procedure>(); + this.absyMap = new Dictionary<Absy, Absy>(); + this.implMap = new Dictionary<Implementation, Implementation>(); + this.yieldingProcs = new HashSet<Procedure>(); + this.impls = new List<Implementation>(); + } + + private void ProcessCallCmd(CallCmd originalCallCmd, CallCmd callCmd, List<Cmd> newCmds) + { + int enclosingProcLayerNum = civlTypeChecker.procToActionInfo[enclosingImpl.Proc].createdAtLayerNum; + Procedure originalProc = originalCallCmd.Proc; + + if (civlTypeChecker.procToAtomicProcedureInfo.ContainsKey(originalProc)) + { + if (civlTypeChecker.CallExists(originalCallCmd, enclosingProcLayerNum, layerNum)) + { + newCmds.Add(callCmd); + } + } + else if (civlTypeChecker.procToActionInfo.ContainsKey(originalProc)) + { + AtomicActionInfo atomicActionInfo = civlTypeChecker.procToActionInfo[originalProc] as AtomicActionInfo; + if (atomicActionInfo != null && atomicActionInfo.gate.Count > 0 && layerNum == enclosingProcLayerNum) + { + newCmds.Add(new HavocCmd(Token.NoToken, new List<IdentifierExpr>(new IdentifierExpr[] { Expr.Ident(dummyLocalVar) }))); + Dictionary<Variable, Expr> map = new Dictionary<Variable, Expr>(); + for (int i = 0; i < originalProc.InParams.Count; i++) + { + map[originalProc.InParams[i]] = callCmd.Ins[i]; + } + Substitution subst = Substituter.SubstitutionFromHashtable(map); + foreach (AssertCmd assertCmd in atomicActionInfo.gate) + { + newCmds.Add(Substituter.Apply(subst, assertCmd)); + } + } + newCmds.Add(callCmd); + } + else + { + Debug.Assert(false); + } + } + + private void ProcessParCallCmd(ParCallCmd originalParCallCmd, ParCallCmd parCallCmd, List<Cmd> newCmds) + { + int maxCalleeLayerNum = 0; + foreach (CallCmd iter in originalParCallCmd.CallCmds) + { + int calleeLayerNum = civlTypeChecker.procToActionInfo[iter.Proc].createdAtLayerNum; + if (calleeLayerNum > maxCalleeLayerNum) + maxCalleeLayerNum = calleeLayerNum; + } + if (layerNum > maxCalleeLayerNum) + { + for (int i = 0; i < parCallCmd.CallCmds.Count; i++) + { + ProcessCallCmd(originalParCallCmd.CallCmds[i], parCallCmd.CallCmds[i], newCmds); + absyMap[parCallCmd.CallCmds[i]] = originalParCallCmd; + } + } + else + { + newCmds.Add(parCallCmd); + } + } + + public override List<Cmd> VisitCmdSeq(List<Cmd> cmdSeq) + { + List<Cmd> cmds = base.VisitCmdSeq(cmdSeq); + List<Cmd> newCmds = new List<Cmd>(); + for (int i = 0; i < cmds.Count; i++) + { + Cmd originalCmd = cmdSeq[i]; + Cmd cmd = cmds[i]; + + CallCmd originalCallCmd = originalCmd as CallCmd; + if (originalCallCmd != null) + { + ProcessCallCmd(originalCallCmd, cmd as CallCmd, newCmds); + continue; + } + + ParCallCmd originalParCallCmd = originalCmd as ParCallCmd; + if (originalParCallCmd != null) + { + ProcessParCallCmd(originalParCallCmd, cmd as ParCallCmd, newCmds); + continue; + } + + newCmds.Add(cmd); + } + return newCmds; + } + + public override YieldCmd VisitYieldCmd(YieldCmd node) + { + YieldCmd yieldCmd = base.VisitYieldCmd(node); + absyMap[yieldCmd] = node; + return yieldCmd; + } + + public override Block VisitBlock(Block node) + { + Block block = base.VisitBlock(node); + absyMap[block] = node; + return block; + } + + public override Cmd VisitCallCmd(CallCmd node) + { + CallCmd callCmd = (CallCmd) base.VisitCallCmd(node); + callCmd.Proc = VisitProcedure(callCmd.Proc); + callCmd.callee = callCmd.Proc.Name; + absyMap[callCmd] = node; + return callCmd; + } + + public override Cmd VisitParCallCmd(ParCallCmd node) + { + ParCallCmd parCallCmd = (ParCallCmd) base.VisitParCallCmd(node); + absyMap[parCallCmd] = node; + return parCallCmd; + } + + public override Procedure VisitProcedure(Procedure node) + { + if (!civlTypeChecker.procToActionInfo.ContainsKey(node)) + return node; + if (!procMap.ContainsKey(node)) + { + enclosingProc = node; + Procedure proc = (Procedure)node.Clone(); + proc.Name = string.Format("{0}_{1}", node.Name, layerNum); + proc.InParams = this.VisitVariableSeq(node.InParams); + proc.Modifies = this.VisitIdentifierExprSeq(node.Modifies); + proc.OutParams = this.VisitVariableSeq(node.OutParams); + + ActionInfo actionInfo = civlTypeChecker.procToActionInfo[node]; + if (actionInfo.createdAtLayerNum < layerNum) + { + proc.Requires = new List<Requires>(); + proc.Ensures = new List<Ensures>(); + Implementation impl; + AtomicActionInfo atomicActionInfo = actionInfo as AtomicActionInfo; + if (atomicActionInfo != null) + { + CodeExpr action = (CodeExpr)VisitCodeExpr(atomicActionInfo.action); + List<Cmd> cmds = new List<Cmd>(); + foreach (AssertCmd assertCmd in atomicActionInfo.gate) + { + cmds.Add(new AssumeCmd(Token.NoToken, (Expr)Visit(assertCmd.Expr))); + } + Block newInitBlock = new Block(Token.NoToken, "_init", cmds, + new GotoCmd(Token.NoToken, new List<string>(new string[] { action.Blocks[0].Label }), + new List<Block>(new Block[] { action.Blocks[0] }))); + List<Block> newBlocks = new List<Block>(); + newBlocks.Add(newInitBlock); + newBlocks.AddRange(action.Blocks); + impl = new Implementation(Token.NoToken, proc.Name, node.TypeParameters, node.InParams, node.OutParams, action.LocVars, newBlocks); + } + else + { + Block newInitBlock = new Block(Token.NoToken, "_init", new List<Cmd>(), new ReturnCmd(Token.NoToken)); + List<Block> newBlocks = new List<Block>(); + newBlocks.Add(newInitBlock); + impl = new Implementation(Token.NoToken, proc.Name, node.TypeParameters, node.InParams, node.OutParams, new List<Variable>(), newBlocks); + } + impl.Proc = proc; + impl.Proc.AddAttribute("inline", new LiteralExpr(Token.NoToken, Microsoft.Basetypes.BigNum.FromInt(1))); + impl.AddAttribute("inline", new LiteralExpr(Token.NoToken, Microsoft.Basetypes.BigNum.FromInt(1))); + impls.Add(impl); + } + else + { + yieldingProcs.Add(proc); + proc.Requires = this.VisitRequiresSeq(node.Requires); + proc.Ensures = this.VisitEnsuresSeq(node.Ensures); + } + procMap[node] = proc; + proc.Modifies = new List<IdentifierExpr>(); + civlTypeChecker.SharedVariables.Iter(x => proc.Modifies.Add(Expr.Ident(x))); + } + return procMap[node]; + } + + private Variable dummyLocalVar; + public override Implementation VisitImplementation(Implementation node) + { + enclosingImpl = node; + dummyLocalVar = new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken, "og_dummy", Type.Bool)); + Implementation impl = base.VisitImplementation(node); + implMap[impl] = node; + impl.LocVars.Add(dummyLocalVar); + impl.Name = impl.Proc.Name; + return impl; + } + + public override Requires VisitRequires(Requires node) + { + Requires requires = base.VisitRequires(node); + if (node.Free) + return requires; + if (!civlTypeChecker.absyToLayerNums[node].Contains(layerNum)) + requires.Condition = Expr.True; + return requires; + } + + public override Ensures VisitEnsures(Ensures node) + { + Ensures ensures = base.VisitEnsures(node); + if (node.Free) + return ensures; + AtomicActionInfo atomicActionInfo = civlTypeChecker.procToActionInfo[enclosingProc] as AtomicActionInfo; + bool isAtomicSpecification = atomicActionInfo != null && atomicActionInfo.ensures == node; + if (isAtomicSpecification || !civlTypeChecker.absyToLayerNums[node].Contains(layerNum)) + { + ensures.Condition = Expr.True; + ensures.Attributes = CivlRefinement.RemoveMoverAttribute(ensures.Attributes); + } + return ensures; + } + + public override Cmd VisitAssertCmd(AssertCmd node) + { + AssertCmd assertCmd = (AssertCmd) base.VisitAssertCmd(node); + if (!civlTypeChecker.absyToLayerNums[node].Contains(layerNum)) + assertCmd.Expr = Expr.True; + return assertCmd; + } + } + + public class CivlRefinement + { + LinearTypeChecker linearTypeChecker; + CivlTypeChecker civlTypeChecker; + Dictionary<Absy, Absy> absyMap; + Dictionary<Implementation, Implementation> implMap; + HashSet<Procedure> yieldingProcs; + int layerNum; + List<IdentifierExpr> globalMods; + Dictionary<string, Procedure> asyncAndParallelCallDesugarings; + List<Procedure> yieldCheckerProcs; + List<Implementation> yieldCheckerImpls; + Procedure yieldProc; + + Variable pc; + Variable ok; + Expr alpha; + Expr beta; + HashSet<Variable> frame; + + public CivlRefinement(LinearTypeChecker linearTypeChecker, CivlTypeChecker civlTypeChecker, MyDuplicator duplicator) + { + this.linearTypeChecker = linearTypeChecker; + this.civlTypeChecker = civlTypeChecker; + this.absyMap = duplicator.absyMap; + this.layerNum = duplicator.layerNum; + this.implMap = duplicator.implMap; + this.yieldingProcs = duplicator.yieldingProcs; + Program program = linearTypeChecker.program; + globalMods = new List<IdentifierExpr>(); + foreach (Variable g in civlTypeChecker.SharedVariables) + { + globalMods.Add(Expr.Ident(g)); + } + asyncAndParallelCallDesugarings = new Dictionary<string, Procedure>(); + yieldCheckerProcs = new List<Procedure>(); + yieldCheckerImpls = new List<Implementation>(); + yieldProc = null; + } + + private IEnumerable<Variable> AvailableLinearVars(Absy absy) + { + HashSet<Variable> availableVars = new HashSet<Variable>(linearTypeChecker.AvailableLinearVars(absyMap[absy])); + foreach (var g in civlTypeChecker.globalVarToSharedVarInfo.Keys) + { + SharedVariableInfo info = civlTypeChecker.globalVarToSharedVarInfo[g]; + if (!(info.introLayerNum <= layerNum && layerNum <= info.hideLayerNum)) + { + availableVars.Remove(g); + } + } + foreach (var v in civlTypeChecker.localVarToLocalVariableInfo.Keys) + { + LocalVariableInfo info = civlTypeChecker.localVarToLocalVariableInfo[v]; + if (layerNum < info.layer) + { + availableVars.Remove(v); + } + } + return availableVars; + } + + private CallCmd CallToYieldProc(IToken tok, Dictionary<Variable, Variable> ogOldGlobalMap, Dictionary<string, Variable> domainNameToLocalVar) + { + List<Expr> exprSeq = new List<Expr>(); + foreach (string domainName in linearTypeChecker.linearDomains.Keys) + { + exprSeq.Add(Expr.Ident(domainNameToLocalVar[domainName])); + } + foreach (IdentifierExpr ie in globalMods) + { + exprSeq.Add(Expr.Ident(ogOldGlobalMap[ie.Decl])); + } + if (yieldProc == null) + { + List<Variable> inputs = new List<Variable>(); + foreach (string domainName in linearTypeChecker.linearDomains.Keys) + { + var domain = linearTypeChecker.linearDomains[domainName]; + Formal f = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "linear_" + domainName + "_in", new MapType(Token.NoToken, new List<TypeVariable>(), new List<Type> { domain.elementType }, Type.Bool)), true); + inputs.Add(f); + } + foreach (IdentifierExpr ie in globalMods) + { + Formal f = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, string.Format("og_global_old_{0}", ie.Decl.Name), ie.Decl.TypedIdent.Type), true); + inputs.Add(f); + } + yieldProc = new Procedure(Token.NoToken, string.Format("og_yield_{0}", layerNum), new List<TypeVariable>(), inputs, new List<Variable>(), new List<Requires>(), new List<IdentifierExpr>(), new List<Ensures>()); + yieldProc.AddAttribute("inline", new LiteralExpr(Token.NoToken, Microsoft.Basetypes.BigNum.FromInt(1))); + } + CallCmd yieldCallCmd = new CallCmd(Token.NoToken, yieldProc.Name, exprSeq, new List<IdentifierExpr>()); + yieldCallCmd.Proc = yieldProc; + return yieldCallCmd; + } + + private void AddCallToYieldProc(IToken tok, List<Cmd> newCmds, Dictionary<Variable, Variable> ogOldGlobalMap, Dictionary<string, Variable> domainNameToLocalVar) + { + if (!CommandLineOptions.Clo.TrustNonInterference) + { + CallCmd yieldCallCmd = CallToYieldProc(tok, ogOldGlobalMap, domainNameToLocalVar); + newCmds.Add(yieldCallCmd); + } + + if (pc != null) + { + Expr aa = OldEqualityExprForGlobals(ogOldGlobalMap); + Expr bb = OldEqualityExpr(ogOldGlobalMap); + + // assert pc || g_old == g || beta(i, g_old, o, g); + Expr assertExpr = Expr.Or(Expr.Ident(pc), Expr.Or(aa, beta)); + assertExpr.Typecheck(new TypecheckingContext(null)); + AssertCmd skipOrBetaAssertCmd = new AssertCmd(tok, assertExpr); + skipOrBetaAssertCmd.ErrorData = "Transition invariant in initial state violated"; + newCmds.Add(skipOrBetaAssertCmd); + + // assert pc ==> o_old == o && g_old == g; + assertExpr = Expr.Imp(Expr.Ident(pc), bb); + assertExpr.Typecheck(new TypecheckingContext(null)); + AssertCmd skipAssertCmd = new AssertCmd(tok, assertExpr); + skipAssertCmd.ErrorData = "Transition invariant in final state violated"; ; + newCmds.Add(skipAssertCmd); + + // pc, ok := g_old == g ==> pc, ok || beta(i, g_old, o, g); + List<AssignLhs> pcUpdateLHS = new List<AssignLhs>( + new AssignLhs[] { + new SimpleAssignLhs(Token.NoToken, Expr.Ident(pc)), + new SimpleAssignLhs(Token.NoToken, Expr.Ident(ok)) + }); + List<Expr> pcUpdateRHS = new List<Expr>( + new Expr[] { + Expr.Imp(aa, Expr.Ident(pc)), + Expr.Or(Expr.Ident(ok), beta) + }); + foreach (Expr e in pcUpdateRHS) + { + e.Typecheck(new TypecheckingContext(null)); + } + newCmds.Add(new AssignCmd(Token.NoToken, pcUpdateLHS, pcUpdateRHS)); + } + } + + private Dictionary<string, Expr> ComputeAvailableExprs(IEnumerable<Variable> availableLinearVars, Dictionary<string, Variable> domainNameToInputVar) + { + Dictionary<string, Expr> domainNameToExpr = new Dictionary<string, Expr>(); + foreach (var domainName in linearTypeChecker.linearDomains.Keys) + { + var expr = Expr.Ident(domainNameToInputVar[domainName]); + expr.Resolve(new ResolutionContext(null)); + expr.Typecheck(new TypecheckingContext(null)); + domainNameToExpr[domainName] = expr; + } + foreach (Variable v in availableLinearVars) + { + var domainName = linearTypeChecker.FindDomainName(v); + if (!linearTypeChecker.linearDomains.ContainsKey(domainName)) continue; + var domain = linearTypeChecker.linearDomains[domainName]; + if (!domain.collectors.ContainsKey(v.TypedIdent.Type)) continue; + Expr ie = new NAryExpr(Token.NoToken, new FunctionCall(domain.collectors[v.TypedIdent.Type]), new List<Expr> { Expr.Ident(v) }); + var expr = new NAryExpr(Token.NoToken, new FunctionCall(domain.mapOrBool), new List<Expr> { ie, domainNameToExpr[domainName] }); + expr.Resolve(new ResolutionContext(null)); + expr.Typecheck(new TypecheckingContext(null)); + domainNameToExpr[domainName] = expr; + } + return domainNameToExpr; + } + + private void AddUpdatesToOldGlobalVars(List<Cmd> newCmds, Dictionary<Variable, Variable> ogOldGlobalMap, Dictionary<string, Variable> domainNameToLocalVar, Dictionary<string, Expr> domainNameToExpr) + { + List<AssignLhs> lhss = new List<AssignLhs>(); + List<Expr> rhss = new List<Expr>(); + foreach (var domainName in linearTypeChecker.linearDomains.Keys) + { + lhss.Add(new SimpleAssignLhs(Token.NoToken, Expr.Ident(domainNameToLocalVar[domainName]))); + rhss.Add(domainNameToExpr[domainName]); + } + foreach (Variable g in ogOldGlobalMap.Keys) + { + lhss.Add(new SimpleAssignLhs(Token.NoToken, Expr.Ident(ogOldGlobalMap[g]))); + rhss.Add(Expr.Ident(g)); + } + if (lhss.Count > 0) + { + newCmds.Add(new AssignCmd(Token.NoToken, lhss, rhss)); + } + } + + private Expr OldEqualityExpr(Dictionary<Variable, Variable> ogOldGlobalMap) + { + Expr bb = Expr.True; + foreach (Variable o in ogOldGlobalMap.Keys) + { + if (o is GlobalVariable && !frame.Contains(o)) continue; + bb = Expr.And(bb, Expr.Eq(Expr.Ident(o), Expr.Ident(ogOldGlobalMap[o]))); + bb.Type = Type.Bool; + } + return bb; + } + + private Expr OldEqualityExprForGlobals(Dictionary<Variable, Variable> ogOldGlobalMap) + { + Expr bb = Expr.True; + foreach (Variable o in ogOldGlobalMap.Keys) + { + if (o is GlobalVariable && frame.Contains(o)) + { + bb = Expr.And(bb, Expr.Eq(Expr.Ident(o), Expr.Ident(ogOldGlobalMap[o]))); + bb.Type = Type.Bool; + } + } + return bb; + } + + private void DesugarYield(YieldCmd yieldCmd, List<Cmd> cmds, List<Cmd> newCmds, Dictionary<Variable, Variable> ogOldGlobalMap, Dictionary<string, Variable> domainNameToInputVar, Dictionary<string, Variable> domainNameToLocalVar) + { + AddCallToYieldProc(yieldCmd.tok, newCmds, ogOldGlobalMap, domainNameToLocalVar); + + if (globalMods.Count > 0) + { + newCmds.Add(new HavocCmd(Token.NoToken, globalMods)); + if (pc != null) + { + // assume pc || alpha(i, g); + Expr assumeExpr = Expr.Or(Expr.Ident(pc), alpha); + assumeExpr.Type = Type.Bool; + newCmds.Add(new AssumeCmd(Token.NoToken, assumeExpr)); + } + } + + Dictionary<string, Expr> domainNameToExpr = ComputeAvailableExprs(AvailableLinearVars(yieldCmd), domainNameToInputVar); + AddUpdatesToOldGlobalVars(newCmds, ogOldGlobalMap, domainNameToLocalVar, domainNameToExpr); + + for (int j = 0; j < cmds.Count; j++) + { + PredicateCmd predCmd = (PredicateCmd)cmds[j]; + newCmds.Add(new AssumeCmd(Token.NoToken, predCmd.Expr)); + } + } + + public void DesugarParallelCallCmd(List<Cmd> newCmds, ParCallCmd parCallCmd) + { + List<string> parallelCalleeNames = new List<string>(); + List<Expr> ins = new List<Expr>(); + List<IdentifierExpr> outs = new List<IdentifierExpr>(); + string procName = "og"; + foreach (CallCmd callCmd in parCallCmd.CallCmds) + { + procName = procName + "_" + callCmd.Proc.Name; + ins.AddRange(callCmd.Ins); + outs.AddRange(callCmd.Outs); + } + Procedure proc; + if (asyncAndParallelCallDesugarings.ContainsKey(procName)) + { + proc = asyncAndParallelCallDesugarings[procName]; + } + else + { + List<Variable> inParams = new List<Variable>(); + List<Variable> outParams = new List<Variable>(); + List<Requires> requiresSeq = new List<Requires>(); + List<Ensures> ensuresSeq = new List<Ensures>(); + int count = 0; + foreach (CallCmd callCmd in parCallCmd.CallCmds) + { + Dictionary<Variable, Expr> map = new Dictionary<Variable, Expr>(); + foreach (Variable x in callCmd.Proc.InParams) + { + Variable y = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, string.Format("og_{0}_{1}", count, x.Name), x.TypedIdent.Type), true); + inParams.Add(y); + map[x] = Expr.Ident(y); + } + foreach (Variable x in callCmd.Proc.OutParams) + { + Variable y = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, string.Format("og_{0}_{1}", count, x.Name), x.TypedIdent.Type), false); + outParams.Add(y); + map[x] = Expr.Ident(y); + } + Contract.Assume(callCmd.Proc.TypeParameters.Count == 0); + Substitution subst = Substituter.SubstitutionFromHashtable(map); + foreach (Requires req in callCmd.Proc.Requires) + { + requiresSeq.Add(new Requires(req.tok, req.Free, Substituter.Apply(subst, req.Condition), null, req.Attributes)); + } + foreach (Ensures ens in callCmd.Proc.Ensures) + { + ensuresSeq.Add(new Ensures(ens.tok, ens.Free, Substituter.Apply(subst, ens.Condition), null, ens.Attributes)); + } + count++; + } + proc = new Procedure(Token.NoToken, procName, new List<TypeVariable>(), inParams, outParams, requiresSeq, globalMods, ensuresSeq); + asyncAndParallelCallDesugarings[procName] = proc; + } + CallCmd dummyCallCmd = new CallCmd(parCallCmd.tok, proc.Name, ins, outs, parCallCmd.Attributes); + dummyCallCmd.Proc = proc; + newCmds.Add(dummyCallCmd); + } + + private void CreateYieldCheckerImpl(Implementation impl, List<List<Cmd>> yields) + { + if (yields.Count == 0) return; + + Dictionary<Variable, Expr> map = new Dictionary<Variable, Expr>(); + foreach (Variable local in impl.LocVars) + { + var copy = new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken, local.Name, local.TypedIdent.Type)); + map[local] = Expr.Ident(copy); + } + + Program program = linearTypeChecker.program; + List<Variable> locals = new List<Variable>(); + List<Variable> inputs = new List<Variable>(); + foreach (IdentifierExpr ie in map.Values) + { + locals.Add(ie.Decl); + } + for (int i = 0; i < impl.InParams.Count - linearTypeChecker.linearDomains.Count; i++) + { + Variable inParam = impl.InParams[i]; + Variable copy = new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken, inParam.Name, inParam.TypedIdent.Type)); + locals.Add(copy); + map[impl.InParams[i]] = Expr.Ident(copy); + } + { + int i = impl.InParams.Count - linearTypeChecker.linearDomains.Count; + foreach (string domainName in linearTypeChecker.linearDomains.Keys) + { + Variable inParam = impl.InParams[i]; + Variable copy = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, inParam.Name, inParam.TypedIdent.Type), true); + inputs.Add(copy); + map[impl.InParams[i]] = Expr.Ident(copy); + i++; + } + } + for (int i = 0; i < impl.OutParams.Count; i++) + { + Variable outParam = impl.OutParams[i]; + var copy = new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken, outParam.Name, outParam.TypedIdent.Type)); + locals.Add(copy); + map[impl.OutParams[i]] = Expr.Ident(copy); + } + Dictionary<Variable, Expr> ogOldLocalMap = new Dictionary<Variable, Expr>(); + Dictionary<Variable, Expr> assumeMap = new Dictionary<Variable, Expr>(map); + foreach (IdentifierExpr ie in globalMods) + { + Variable g = ie.Decl; + var copy = new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken, string.Format("og_local_old_{0}", g.Name), g.TypedIdent.Type)); + locals.Add(copy); + ogOldLocalMap[g] = Expr.Ident(copy); + Formal f = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, string.Format("og_global_old_{0}", g.Name), g.TypedIdent.Type), true); + inputs.Add(f); + assumeMap[g] = Expr.Ident(f); + } + + Substitution assumeSubst = Substituter.SubstitutionFromHashtable(assumeMap); + Substitution oldSubst = Substituter.SubstitutionFromHashtable(ogOldLocalMap); + Substitution subst = Substituter.SubstitutionFromHashtable(map); + List<Block> yieldCheckerBlocks = new List<Block>(); + List<String> labels = new List<String>(); + List<Block> labelTargets = new List<Block>(); + Block yieldCheckerBlock = new Block(Token.NoToken, "exit", new List<Cmd>(), new ReturnCmd(Token.NoToken)); + labels.Add(yieldCheckerBlock.Label); + labelTargets.Add(yieldCheckerBlock); + yieldCheckerBlocks.Add(yieldCheckerBlock); + int yieldCount = 0; + foreach (List<Cmd> cs in yields) + { + List<Cmd> newCmds = new List<Cmd>(); + foreach (Cmd cmd in cs) + { + PredicateCmd predCmd = (PredicateCmd)cmd; + newCmds.Add(new AssumeCmd(Token.NoToken, Substituter.ApplyReplacingOldExprs(assumeSubst, oldSubst, predCmd.Expr))); + } + foreach (Cmd cmd in cs) + { + PredicateCmd predCmd = (PredicateCmd)cmd; + var newExpr = Substituter.ApplyReplacingOldExprs(subst, oldSubst, predCmd.Expr); + if (predCmd is AssertCmd) + { + AssertCmd assertCmd = new AssertCmd(predCmd.tok, newExpr, predCmd.Attributes); + assertCmd.ErrorData = "Non-interference check failed"; + newCmds.Add(assertCmd); + } + else + { + newCmds.Add(new AssumeCmd(Token.NoToken, newExpr)); + } + } + newCmds.Add(new AssumeCmd(Token.NoToken, Expr.False)); + yieldCheckerBlock = new Block(Token.NoToken, "L" + yieldCount++, newCmds, new ReturnCmd(Token.NoToken)); + labels.Add(yieldCheckerBlock.Label); + labelTargets.Add(yieldCheckerBlock); + yieldCheckerBlocks.Add(yieldCheckerBlock); + } + yieldCheckerBlocks.Insert(0, new Block(Token.NoToken, "enter", new List<Cmd>(), new GotoCmd(Token.NoToken, labels, labelTargets))); + + // Create the yield checker procedure + var yieldCheckerName = string.Format("{0}_YieldChecker_{1}", "Impl", impl.Name); + var yieldCheckerProc = new Procedure(Token.NoToken, yieldCheckerName, impl.TypeParameters, inputs, new List<Variable>(), new List<Requires>(), new List<IdentifierExpr>(), new List<Ensures>()); + yieldCheckerProc.AddAttribute("inline", new LiteralExpr(Token.NoToken, Microsoft.Basetypes.BigNum.FromInt(1))); + yieldCheckerProcs.Add(yieldCheckerProc); + + // Create the yield checker implementation + var yieldCheckerImpl = new Implementation(Token.NoToken, yieldCheckerName, impl.TypeParameters, inputs, new List<Variable>(), locals, yieldCheckerBlocks); + yieldCheckerImpl.Proc = yieldCheckerProc; + yieldCheckerImpl.AddAttribute("inline", new LiteralExpr(Token.NoToken, Microsoft.Basetypes.BigNum.FromInt(1))); + yieldCheckerImpls.Add(yieldCheckerImpl); + } + + private bool IsYieldingHeader(Graph<Block> graph, Block header) + { + foreach (Block backEdgeNode in graph.BackEdgeNodes(header)) + { + foreach (Block x in graph.NaturalLoops(header, backEdgeNode)) + { + foreach (Cmd cmd in x.Cmds) + { + if (cmd is YieldCmd) + return true; + if (cmd is ParCallCmd) + return true; + CallCmd callCmd = cmd as CallCmd; + if (callCmd == null) continue; + if (yieldingProcs.Contains(callCmd.Proc)) + return true; + } + } + } + return false; + } + + private Graph<Block> ComputeYieldingLoopHeaders(Implementation impl, out HashSet<Block> yieldingHeaders) + { + Graph<Block> graph; + impl.PruneUnreachableBlocks(); + impl.ComputePredecessorsForBlocks(); + graph = Program.GraphFromImpl(impl); + graph.ComputeLoops(); + if (!graph.Reducible) + { + throw new Exception("Irreducible flow graphs are unsupported."); + } + yieldingHeaders = new HashSet<Block>(); + IEnumerable<Block> sortedHeaders = graph.SortHeadersByDominance(); + foreach (Block header in sortedHeaders) + { + if (yieldingHeaders.Any(x => graph.DominatorMap.DominatedBy(x, header))) + { + yieldingHeaders.Add(header); + } + else if (IsYieldingHeader(graph, header)) + { + yieldingHeaders.Add(header); + } + else + { + continue; + } + } + return graph; + } + + private void SetupRefinementCheck(Implementation impl, + out List<Variable> newLocalVars, + out Dictionary<string, Variable> domainNameToInputVar, out Dictionary<string, Variable> domainNameToLocalVar, out Dictionary<Variable, Variable> ogOldGlobalMap) + { + pc = null; + ok = null; + alpha = null; + beta = null; + frame = null; + + newLocalVars = new List<Variable>(); + Program program = linearTypeChecker.program; + ogOldGlobalMap = new Dictionary<Variable, Variable>(); + foreach (IdentifierExpr ie in globalMods) + { + Variable g = ie.Decl; + LocalVariable l = new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken, string.Format("og_global_old_{0}", g.Name), g.TypedIdent.Type)); + ogOldGlobalMap[g] = l; + newLocalVars.Add(l); + } + + Procedure originalProc = implMap[impl].Proc; + ActionInfo actionInfo = civlTypeChecker.procToActionInfo[originalProc]; + if (actionInfo.createdAtLayerNum == this.layerNum) + { + pc = new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken, "og_pc", Type.Bool)); + newLocalVars.Add(pc); + ok = new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken, "og_ok", Type.Bool)); + newLocalVars.Add(ok); + Dictionary<Variable, Expr> alwaysMap = new Dictionary<Variable, Expr>(); + for (int i = 0; i < originalProc.InParams.Count; i++) + { + alwaysMap[originalProc.InParams[i]] = Expr.Ident(impl.InParams[i]); + } + for (int i = 0; i < originalProc.OutParams.Count; i++) + { + alwaysMap[originalProc.OutParams[i]] = Expr.Ident(impl.OutParams[i]); + } + Substitution always = Substituter.SubstitutionFromHashtable(alwaysMap); + Dictionary<Variable, Expr> foroldMap = new Dictionary<Variable, Expr>(); + foreach (IdentifierExpr ie in globalMods) + { + foroldMap[ie.Decl] = Expr.Ident(ogOldGlobalMap[ie.Decl]); + } + Substitution forold = Substituter.SubstitutionFromHashtable(foroldMap); + frame = new HashSet<Variable>(civlTypeChecker.SharedVariables); + foreach (Variable v in civlTypeChecker.SharedVariables) + { + if (civlTypeChecker.globalVarToSharedVarInfo[v].hideLayerNum <= actionInfo.createdAtLayerNum || + civlTypeChecker.globalVarToSharedVarInfo[v].introLayerNum > actionInfo.createdAtLayerNum) + { + frame.Remove(v); + } + } + AtomicActionInfo atomicActionInfo = actionInfo as AtomicActionInfo; + if (atomicActionInfo == null) + { + beta = Expr.True; + foreach (var v in frame) + { + beta = Expr.And(beta, Expr.Eq(Expr.Ident(v), foroldMap[v])); + } + alpha = Expr.True; + } + else + { + Expr betaExpr = (new MoverCheck.TransitionRelationComputation(civlTypeChecker.program, atomicActionInfo, frame, new HashSet<Variable>())).TransitionRelationCompute(true); + beta = Substituter.ApplyReplacingOldExprs(always, forold, betaExpr); + Expr alphaExpr = Expr.True; + foreach (AssertCmd assertCmd in atomicActionInfo.gate) + { + alphaExpr = Expr.And(alphaExpr, assertCmd.Expr); + alphaExpr.Type = Type.Bool; + } + alpha = Substituter.Apply(always, alphaExpr); + } + foreach (Variable f in impl.OutParams) + { + LocalVariable copy = new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken, string.Format("og_old_{0}", f.Name), f.TypedIdent.Type)); + newLocalVars.Add(copy); + ogOldGlobalMap[f] = copy; + } + } + + domainNameToInputVar = new Dictionary<string, Variable>(); + domainNameToLocalVar = new Dictionary<string, Variable>(); + { + int i = impl.InParams.Count - linearTypeChecker.linearDomains.Count; + foreach (string domainName in linearTypeChecker.linearDomains.Keys) + { + Variable inParam = impl.InParams[i]; + domainNameToInputVar[domainName] = inParam; + Variable l = new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken, inParam.Name + "_local", inParam.TypedIdent.Type)); + domainNameToLocalVar[domainName] = l; + newLocalVars.Add(l); + i++; + } + } + } + + private void TransformImpl(Implementation impl) + { + HashSet<Block> yieldingHeaders; + Graph<Block> graph = ComputeYieldingLoopHeaders(impl, out yieldingHeaders); + + List<Variable> newLocalVars; + Dictionary<string, Variable> domainNameToInputVar, domainNameToLocalVar; + Dictionary<Variable, Variable> ogOldGlobalMap; + SetupRefinementCheck(impl, out newLocalVars, out domainNameToInputVar, out domainNameToLocalVar, out ogOldGlobalMap); + + List<List<Cmd>> yields = CollectAndDesugarYields(impl, domainNameToInputVar, domainNameToLocalVar, ogOldGlobalMap); + + List<Variable> oldPcs, oldOks; + ProcessLoopHeaders(impl, graph, yieldingHeaders, domainNameToInputVar, domainNameToLocalVar, ogOldGlobalMap, out oldPcs, out oldOks); + + AddInitialBlock(impl, oldPcs, oldOks, domainNameToInputVar, domainNameToLocalVar, ogOldGlobalMap); + + CreateYieldCheckerImpl(impl, yields); + + impl.LocVars.AddRange(newLocalVars); + impl.LocVars.AddRange(oldPcs); + impl.LocVars.AddRange(oldOks); + + UnifyCallsToYieldProc(impl, ogOldGlobalMap, domainNameToLocalVar); + } + + private void UnifyCallsToYieldProc(Implementation impl, Dictionary<Variable, Variable> ogOldGlobalMap, Dictionary<string, Variable> domainNameToLocalVar) + { + CallCmd yieldCallCmd = CallToYieldProc(Token.NoToken, ogOldGlobalMap, domainNameToLocalVar); + Block yieldCheckBlock = new Block(Token.NoToken, "CallToYieldProc", new List<Cmd>(new Cmd[] { yieldCallCmd, new AssumeCmd(Token.NoToken, Expr.False) }), new ReturnCmd(Token.NoToken)); + List<Block> newBlocks = new List<Block>(); + foreach (Block b in impl.Blocks) + { + TransferCmd transferCmd = b.TransferCmd; + List<Cmd> newCmds = new List<Cmd>(); + for (int i = b.Cmds.Count-1; i >= 0; i--) + { + CallCmd callCmd = b.Cmds[i] as CallCmd; + if (callCmd == null || callCmd.Proc != yieldProc) + { + newCmds.Insert(0, b.Cmds[i]); + } + else + { + Block newBlock = new Block(Token.NoToken, b.Label + i, newCmds, transferCmd); + newCmds = new List<Cmd>(); + transferCmd = new GotoCmd(Token.NoToken, new List<string>(new string[] { newBlock.Label, yieldCheckBlock.Label }), + new List<Block>(new Block[] { newBlock, yieldCheckBlock })); + newBlocks.Add(newBlock); + } + } + b.Cmds = newCmds; + b.TransferCmd = transferCmd; + } + impl.Blocks.AddRange(newBlocks); + impl.Blocks.Add(yieldCheckBlock); + } + + private List<List<Cmd>> CollectAndDesugarYields(Implementation impl, + Dictionary<string, Variable> domainNameToInputVar, Dictionary<string, Variable> domainNameToLocalVar, Dictionary<Variable, Variable> ogOldGlobalMap) + { + // Collect the yield predicates and desugar yields + List<List<Cmd>> yields = new List<List<Cmd>>(); + List<Cmd> cmds = new List<Cmd>(); + foreach (Block b in impl.Blocks) + { + YieldCmd yieldCmd = null; + List<Cmd> newCmds = new List<Cmd>(); + for (int i = 0; i < b.Cmds.Count; i++) + { + Cmd cmd = b.Cmds[i]; + if (cmd is YieldCmd) + { + yieldCmd = (YieldCmd)cmd; + continue; + } + if (yieldCmd != null) + { + PredicateCmd pcmd = cmd as PredicateCmd; + if (pcmd == null) + { + DesugarYield(yieldCmd, cmds, newCmds, ogOldGlobalMap, domainNameToInputVar, domainNameToLocalVar); + if (cmds.Count > 0) + { + yields.Add(cmds); + cmds = new List<Cmd>(); + } + yieldCmd = null; + } + else + { + cmds.Add(pcmd); + } + } + + if (cmd is CallCmd) + { + CallCmd callCmd = cmd as CallCmd; + if (yieldingProcs.Contains(callCmd.Proc)) + { + AddCallToYieldProc(callCmd.tok, newCmds, ogOldGlobalMap, domainNameToLocalVar); + } + if (callCmd.IsAsync) + { + if (!asyncAndParallelCallDesugarings.ContainsKey(callCmd.Proc.Name)) + { + asyncAndParallelCallDesugarings[callCmd.Proc.Name] = new Procedure(Token.NoToken, string.Format("DummyAsyncTarget_{0}", callCmd.Proc.Name), callCmd.Proc.TypeParameters, callCmd.Proc.InParams, callCmd.Proc.OutParams, callCmd.Proc.Requires, new List<IdentifierExpr>(), new List<Ensures>()); + } + var dummyAsyncTargetProc = asyncAndParallelCallDesugarings[callCmd.Proc.Name]; + CallCmd dummyCallCmd = new CallCmd(callCmd.tok, dummyAsyncTargetProc.Name, callCmd.Ins, callCmd.Outs, callCmd.Attributes); + dummyCallCmd.Proc = dummyAsyncTargetProc; + newCmds.Add(dummyCallCmd); + } + else + { + newCmds.Add(callCmd); + } + if (yieldingProcs.Contains(callCmd.Proc)) + { + HashSet<Variable> availableLinearVars = new HashSet<Variable>(AvailableLinearVars(callCmd)); + linearTypeChecker.AddAvailableVars(callCmd, availableLinearVars); + + if (!callCmd.IsAsync && globalMods.Count > 0 && pc != null) + { + // assume pc || alpha(i, g); + Expr assumeExpr = Expr.Or(Expr.Ident(pc), alpha); + assumeExpr.Type = Type.Bool; + newCmds.Add(new AssumeCmd(Token.NoToken, assumeExpr)); + } + + Dictionary<string, Expr> domainNameToExpr = ComputeAvailableExprs(availableLinearVars, domainNameToInputVar); + AddUpdatesToOldGlobalVars(newCmds, ogOldGlobalMap, domainNameToLocalVar, domainNameToExpr); + } + } + else if (cmd is ParCallCmd) + { + ParCallCmd parCallCmd = cmd as ParCallCmd; + AddCallToYieldProc(parCallCmd.tok, newCmds, ogOldGlobalMap, domainNameToLocalVar); + DesugarParallelCallCmd(newCmds, parCallCmd); + HashSet<Variable> availableLinearVars = new HashSet<Variable>(AvailableLinearVars(parCallCmd)); + linearTypeChecker.AddAvailableVars(parCallCmd, availableLinearVars); + + if (globalMods.Count > 0 && pc != null) + { + // assume pc || alpha(i, g); + Expr assumeExpr = Expr.Or(Expr.Ident(pc), alpha); + assumeExpr.Type = Type.Bool; + newCmds.Add(new AssumeCmd(Token.NoToken, assumeExpr)); + } + + Dictionary<string, Expr> domainNameToExpr = ComputeAvailableExprs(availableLinearVars, domainNameToInputVar); + AddUpdatesToOldGlobalVars(newCmds, ogOldGlobalMap, domainNameToLocalVar, domainNameToExpr); + } + else + { + newCmds.Add(cmd); + } + } + if (yieldCmd != null) + { + DesugarYield(yieldCmd, cmds, newCmds, ogOldGlobalMap, domainNameToInputVar, domainNameToLocalVar); + if (cmds.Count > 0) + { + yields.Add(cmds); + cmds = new List<Cmd>(); + } + } + if (b.TransferCmd is ReturnCmd) + { + AddCallToYieldProc(b.TransferCmd.tok, newCmds, ogOldGlobalMap, domainNameToLocalVar); + if (pc != null) + { + AssertCmd assertCmd = new AssertCmd(b.TransferCmd.tok, Expr.Ident(ok)); + assertCmd.ErrorData = "Failed to execute atomic action before procedure return"; + newCmds.Add(assertCmd); + } + } + b.Cmds = newCmds; + } + return yields; + } + + private void ProcessLoopHeaders(Implementation impl, Graph<Block> graph, HashSet<Block> yieldingHeaders, + Dictionary<string, Variable> domainNameToInputVar, Dictionary<string, Variable> domainNameToLocalVar, Dictionary<Variable, Variable> ogOldGlobalMap, + out List<Variable> oldPcs, out List<Variable> oldOks) + { + oldPcs = new List<Variable>(); + oldOks = new List<Variable>(); + foreach (Block header in yieldingHeaders) + { + LocalVariable oldPc = null; + LocalVariable oldOk = null; + if (pc != null) + { + oldPc = new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken, string.Format("{0}_{1}", pc.Name, header.Label), Type.Bool)); + oldPcs.Add(oldPc); + oldOk = new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken, string.Format("{0}_{1}", ok.Name, header.Label), Type.Bool)); + oldOks.Add(oldOk); + } + Dictionary<string, Expr> domainNameToExpr = ComputeAvailableExprs(AvailableLinearVars(header), domainNameToInputVar); + foreach (Block pred in header.Predecessors) + { + AddCallToYieldProc(header.tok, pred.Cmds, ogOldGlobalMap, domainNameToLocalVar); + if (pc != null && !graph.BackEdgeNodes(header).Contains(pred)) + { + pred.Cmds.Add(new AssignCmd(Token.NoToken, new List<AssignLhs>( + new AssignLhs[] { new SimpleAssignLhs(Token.NoToken, Expr.Ident(oldPc)), new SimpleAssignLhs(Token.NoToken, Expr.Ident(oldOk)) }), + new List<Expr>(new Expr[] { Expr.Ident(pc), Expr.Ident(ok) }))); + } + AddUpdatesToOldGlobalVars(pred.Cmds, ogOldGlobalMap, domainNameToLocalVar, domainNameToExpr); + } + List<Cmd> newCmds = new List<Cmd>(); + if (pc != null) + { + AssertCmd assertCmd; + assertCmd = new AssertCmd(header.tok, Expr.Eq(Expr.Ident(oldPc), Expr.Ident(pc))); + assertCmd.ErrorData = "Specification state must not change for transitions ending in loop headers"; + newCmds.Add(assertCmd); + assertCmd = new AssertCmd(header.tok, Expr.Imp(Expr.Ident(oldOk), Expr.Ident(ok))); + assertCmd.ErrorData = "Specification state must not change for transitions ending in loop headers"; + newCmds.Add(assertCmd); + } + foreach (string domainName in linearTypeChecker.linearDomains.Keys) + { + newCmds.Add(new AssumeCmd(Token.NoToken, Expr.Eq(Expr.Ident(domainNameToLocalVar[domainName]), domainNameToExpr[domainName]))); + } + foreach (Variable v in ogOldGlobalMap.Keys) + { + newCmds.Add(new AssumeCmd(Token.NoToken, Expr.Eq(Expr.Ident(v), Expr.Ident(ogOldGlobalMap[v])))); + } + newCmds.AddRange(header.Cmds); + header.Cmds = newCmds; + } + } + + private void AddInitialBlock(Implementation impl, List<Variable> oldPcs, List<Variable> oldOks, + Dictionary<string, Variable> domainNameToInputVar, Dictionary<string, Variable> domainNameToLocalVar, Dictionary<Variable, Variable> ogOldGlobalMap) + { + // Add initial block + List<AssignLhs> lhss = new List<AssignLhs>(); + List<Expr> rhss = new List<Expr>(); + if (pc != null) + { + lhss.Add(new SimpleAssignLhs(Token.NoToken, Expr.Ident(pc))); + rhss.Add(Expr.False); + foreach (Variable oldPc in oldPcs) + { + lhss.Add(new SimpleAssignLhs(Token.NoToken, Expr.Ident(oldPc))); + rhss.Add(Expr.False); + } + lhss.Add(new SimpleAssignLhs(Token.NoToken, Expr.Ident(ok))); + rhss.Add(Expr.False); + foreach (Variable oldOk in oldOks) + { + lhss.Add(new SimpleAssignLhs(Token.NoToken, Expr.Ident(oldOk))); + rhss.Add(Expr.False); + } + } + Dictionary<string, Expr> domainNameToExpr = new Dictionary<string, Expr>(); + foreach (var domainName in linearTypeChecker.linearDomains.Keys) + { + domainNameToExpr[domainName] = Expr.Ident(domainNameToInputVar[domainName]); + } + for (int i = 0; i < impl.InParams.Count - linearTypeChecker.linearDomains.Count; i++) + { + Variable v = impl.InParams[i]; + var domainName = linearTypeChecker.FindDomainName(v); + if (domainName == null) continue; + if (!linearTypeChecker.linearDomains.ContainsKey(domainName)) continue; + var domain = linearTypeChecker.linearDomains[domainName]; + if (!domain.collectors.ContainsKey(v.TypedIdent.Type)) continue; + Expr ie = new NAryExpr(Token.NoToken, new FunctionCall(domain.collectors[v.TypedIdent.Type]), new List<Expr> { Expr.Ident(v) }); + domainNameToExpr[domainName] = new NAryExpr(Token.NoToken, new FunctionCall(domain.mapOrBool), new List<Expr> { ie, domainNameToExpr[domainName] }); + } + foreach (string domainName in linearTypeChecker.linearDomains.Keys) + { + lhss.Add(new SimpleAssignLhs(Token.NoToken, Expr.Ident(domainNameToLocalVar[domainName]))); + rhss.Add(domainNameToExpr[domainName]); + } + foreach (Variable g in ogOldGlobalMap.Keys) + { + lhss.Add(new SimpleAssignLhs(Token.NoToken, Expr.Ident(ogOldGlobalMap[g]))); + rhss.Add(Expr.Ident(g)); + } + if (lhss.Count > 0) + { + Block initBlock = new Block(Token.NoToken, "og_init", new List<Cmd> { new AssignCmd(Token.NoToken, lhss, rhss) }, new GotoCmd(Token.NoToken, new List<String> { impl.Blocks[0].Label }, new List<Block> { impl.Blocks[0] })); + impl.Blocks.Insert(0, initBlock); + } + } + + private void AddYieldProcAndImpl(List<Declaration> decls) + { + if (yieldProc == null) return; + + Program program = linearTypeChecker.program; + List<Variable> inputs = new List<Variable>(); + foreach (string domainName in linearTypeChecker.linearDomains.Keys) + { + var domain = linearTypeChecker.linearDomains[domainName]; + Formal f = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "linear_" + domainName + "_in", new MapType(Token.NoToken, new List<TypeVariable>(), new List<Type> { domain.elementType }, Type.Bool)), true); + inputs.Add(f); + } + foreach (IdentifierExpr ie in globalMods) + { + Formal f = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, string.Format("og_global_old_{0}", ie.Decl.Name), ie.Decl.TypedIdent.Type), true); + inputs.Add(f); + } + List<Block> blocks = new List<Block>(); + TransferCmd transferCmd = new ReturnCmd(Token.NoToken); + if (yieldCheckerProcs.Count > 0) + { + List<Block> blockTargets = new List<Block>(); + List<String> labelTargets = new List<String>(); + int labelCount = 0; + foreach (Procedure proc in yieldCheckerProcs) + { + List<Expr> exprSeq = new List<Expr>(); + foreach (Variable v in inputs) + { + exprSeq.Add(Expr.Ident(v)); + } + CallCmd callCmd = new CallCmd(Token.NoToken, proc.Name, exprSeq, new List<IdentifierExpr>()); + callCmd.Proc = proc; + string label = string.Format("L_{0}", labelCount++); + Block block = new Block(Token.NoToken, label, new List<Cmd> { callCmd }, new ReturnCmd(Token.NoToken)); + labelTargets.Add(label); + blockTargets.Add(block); + blocks.Add(block); + } + transferCmd = new GotoCmd(Token.NoToken, labelTargets, blockTargets); + } + blocks.Insert(0, new Block(Token.NoToken, "enter", new List<Cmd>(), transferCmd)); + + var yieldImpl = new Implementation(Token.NoToken, yieldProc.Name, new List<TypeVariable>(), inputs, new List<Variable>(), new List<Variable>(), blocks); + yieldImpl.Proc = yieldProc; + yieldImpl.AddAttribute("inline", new LiteralExpr(Token.NoToken, Microsoft.Basetypes.BigNum.FromInt(1))); + decls.Add(yieldProc); + decls.Add(yieldImpl); + } + + public static QKeyValue RemoveYieldsAttribute(QKeyValue iter) + { + if (iter == null) return null; + iter.Next = RemoveYieldsAttribute(iter.Next); + return (iter.Key == "yields") ? iter.Next : iter; + } + + public static QKeyValue RemoveMoverAttribute(QKeyValue iter) + { + if (iter == null) return null; + iter.Next = RemoveMoverAttribute(iter.Next); + if (iter.Key == "atomic" || iter.Key == "right" || iter.Key == "left" || iter.Key == "both") + return iter.Next; + else + return iter; + } + + private List<Declaration> Collect() + { + List<Declaration> decls = new List<Declaration>(); + foreach (Procedure proc in yieldCheckerProcs) + { + decls.Add(proc); + } + foreach (Implementation impl in yieldCheckerImpls) + { + decls.Add(impl); + } + foreach (Procedure proc in asyncAndParallelCallDesugarings.Values) + { + decls.Add(proc); + } + AddYieldProcAndImpl(decls); + return decls; + } + + public static void AddCheckers(LinearTypeChecker linearTypeChecker, CivlTypeChecker civlTypeChecker, List<Declaration> decls) + { + Program program = linearTypeChecker.program; + foreach (int layerNum in civlTypeChecker.AllLayerNums) + { + if (CommandLineOptions.Clo.TrustLayersDownto <= layerNum || layerNum <= CommandLineOptions.Clo.TrustLayersUpto) continue; + + MyDuplicator duplicator = new MyDuplicator(civlTypeChecker, layerNum); + foreach (var proc in program.Procedures) + { + if (!civlTypeChecker.procToActionInfo.ContainsKey(proc)) continue; + Procedure duplicateProc = duplicator.VisitProcedure(proc); + decls.Add(duplicateProc); + } + decls.AddRange(duplicator.impls); + CivlRefinement civlTransform = new CivlRefinement(linearTypeChecker, civlTypeChecker, duplicator); + foreach (var impl in program.Implementations) + { + if (!civlTypeChecker.procToActionInfo.ContainsKey(impl.Proc) || civlTypeChecker.procToActionInfo[impl.Proc].createdAtLayerNum < layerNum) + continue; + Implementation duplicateImpl = duplicator.VisitImplementation(impl); + civlTransform.TransformImpl(duplicateImpl); + decls.Add(duplicateImpl); + } + decls.AddRange(civlTransform.Collect()); + } + } + } +} diff --git a/Source/Concurrency/CivlTypeChecker.cs b/Source/Concurrency/CivlTypeChecker.cs new file mode 100644 index 00000000..b426d9ed --- /dev/null +++ b/Source/Concurrency/CivlTypeChecker.cs @@ -0,0 +1,1160 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Microsoft.Boogie; +using System.Diagnostics.Contracts; +using System.Diagnostics; + +namespace Microsoft.Boogie +{ + public enum MoverType + { + Top, + Atomic, + Right, + Left, + Both + } + + public class ActionInfo + { + public Procedure proc; + public int createdAtLayerNum; + public int availableUptoLayerNum; + public bool hasImplementation; + public bool isExtern; + + public ActionInfo(Procedure proc, int createdAtLayerNum, int availableUptoLayerNum) + { + this.proc = proc; + this.createdAtLayerNum = createdAtLayerNum; + this.availableUptoLayerNum = availableUptoLayerNum; + this.hasImplementation = false; + this.isExtern = QKeyValue.FindBoolAttribute(proc.Attributes, "extern"); + } + + public virtual bool IsRightMover + { + get { return true; } + } + + public virtual bool IsLeftMover + { + get { return true; } + } + } + + public class AtomicActionInfo : ActionInfo + { + public Ensures ensures; + public MoverType moverType; + public List<AssertCmd> gate; + public CodeExpr action; + public List<AssertCmd> thisGate; + public CodeExpr thisAction; + public List<Variable> thisInParams; + public List<Variable> thisOutParams; + public List<AssertCmd> thatGate; + public CodeExpr thatAction; + public List<Variable> thatInParams; + public List<Variable> thatOutParams; + public HashSet<Variable> actionUsedGlobalVars; + public HashSet<Variable> modifiedGlobalVars; + public HashSet<Variable> gateUsedGlobalVars; + public bool hasAssumeCmd; + public Dictionary<Variable, Expr> thisMap; + public Dictionary<Variable, Expr> thatMap; + + public bool CommutesWith(AtomicActionInfo actionInfo) + { + if (this.modifiedGlobalVars.Intersect(actionInfo.actionUsedGlobalVars).Count() > 0) + return false; + if (this.actionUsedGlobalVars.Intersect(actionInfo.modifiedGlobalVars).Count() > 0) + return false; + return true; + } + + public override bool IsRightMover + { + get { return moverType == MoverType.Right || moverType == MoverType.Both; } + } + + public override bool IsLeftMover + { + get { return moverType == MoverType.Left || moverType == MoverType.Both; } + } + + public AtomicActionInfo(Procedure proc, Ensures ensures, MoverType moverType, int layerNum, int availableUptoLayerNum) + : base(proc, layerNum, availableUptoLayerNum) + { + this.ensures = ensures; + this.moverType = moverType; + this.gate = new List<AssertCmd>(); + this.action = ensures.Condition as CodeExpr; + this.thisGate = new List<AssertCmd>(); + this.thisInParams = new List<Variable>(); + this.thisOutParams = new List<Variable>(); + this.thatGate = new List<AssertCmd>(); + this.thatInParams = new List<Variable>(); + this.thatOutParams = new List<Variable>(); + this.hasAssumeCmd = false; + this.thisMap = new Dictionary<Variable, Expr>(); + this.thatMap = new Dictionary<Variable, Expr>(); + + foreach (Block block in this.action.Blocks) + { + block.Cmds.ForEach(x => this.hasAssumeCmd = this.hasAssumeCmd || x is AssumeCmd); + } + + foreach (Block block in this.action.Blocks) + { + if (block.TransferCmd is ReturnExprCmd) + { + block.TransferCmd = new ReturnCmd(block.TransferCmd.tok); + } + } + + var cmds = this.action.Blocks[0].Cmds; + for (int i = 0; i < cmds.Count; i++) + { + AssertCmd assertCmd = cmds[i] as AssertCmd; + if (assertCmd == null) break; + this.gate.Add(assertCmd); + cmds[i] = new AssumeCmd(assertCmd.tok, Expr.True); + } + + foreach (Variable x in proc.InParams) + { + Variable thisx = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "this_" + x.Name, x.TypedIdent.Type), true, x.Attributes); + this.thisInParams.Add(thisx); + this.thisMap[x] = Expr.Ident(thisx); + Variable thatx = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "that_" + x.Name, x.TypedIdent.Type), true, x.Attributes); + this.thatInParams.Add(thatx); + this.thatMap[x] = Expr.Ident(thatx); + } + foreach (Variable x in proc.OutParams) + { + Variable thisx = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "this_" + x.Name, x.TypedIdent.Type), false, x.Attributes); + this.thisOutParams.Add(thisx); + this.thisMap[x] = Expr.Ident(thisx); + Variable thatx = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "that_" + x.Name, x.TypedIdent.Type), false, x.Attributes); + this.thatOutParams.Add(thatx); + this.thatMap[x] = Expr.Ident(thatx); + } + List<Variable> thisLocVars = new List<Variable>(); + List<Variable> thatLocVars = new List<Variable>(); + foreach (Variable x in this.action.LocVars) + { + Variable thisx = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "this_" + x.Name, x.TypedIdent.Type), false); + thisMap[x] = Expr.Ident(thisx); + thisLocVars.Add(thisx); + Variable thatx = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "that_" + x.Name, x.TypedIdent.Type), false); + thatMap[x] = Expr.Ident(thatx); + thatLocVars.Add(thatx); + } + Contract.Assume(proc.TypeParameters.Count == 0); + Substitution thisSubst = Substituter.SubstitutionFromHashtable(this.thisMap); + Substitution thatSubst = Substituter.SubstitutionFromHashtable(this.thatMap); + foreach (AssertCmd assertCmd in this.gate) + { + this.thisGate.Add((AssertCmd)Substituter.Apply(thisSubst, assertCmd)); + this.thatGate.Add((AssertCmd)Substituter.Apply(thatSubst, assertCmd)); + } + this.thisAction = new CodeExpr(thisLocVars, SubstituteBlocks(this.action.Blocks, thisSubst, "this_")); + this.thatAction = new CodeExpr(thatLocVars, SubstituteBlocks(this.action.Blocks, thatSubst, "that_")); + + { + VariableCollector collector = new VariableCollector(); + collector.Visit(this.action); + this.actionUsedGlobalVars = new HashSet<Variable>(collector.usedVars.Where(x => x is GlobalVariable)); + } + + List<Variable> modifiedVars = new List<Variable>(); + foreach (Block block in this.action.Blocks) + { + block.Cmds.ForEach(cmd => cmd.AddAssignedVariables(modifiedVars)); + } + this.modifiedGlobalVars = new HashSet<Variable>(modifiedVars.Where(x => x is GlobalVariable)); + + { + VariableCollector collector = new VariableCollector(); + this.gate.ForEach(assertCmd => collector.Visit(assertCmd)); + this.gateUsedGlobalVars = new HashSet<Variable>(collector.usedVars.Where(x => x is GlobalVariable)); + } + } + + private List<Block> SubstituteBlocks(List<Block> blocks, Substitution subst, string blockLabelPrefix) + { + Dictionary<Block, Block> blockMap = new Dictionary<Block, Block>(); + List<Block> otherBlocks = new List<Block>(); + foreach (Block block in blocks) + { + List<Cmd> otherCmds = new List<Cmd>(); + foreach (Cmd cmd in block.Cmds) + { + otherCmds.Add(Substituter.Apply(subst, cmd)); + } + Block otherBlock = new Block(); + otherBlock.Cmds = otherCmds; + otherBlock.Label = blockLabelPrefix + block.Label; + otherBlocks.Add(otherBlock); + blockMap[block] = otherBlock; + } + foreach (Block block in blocks) + { + if (block.TransferCmd is ReturnCmd) + { + blockMap[block].TransferCmd = new ReturnCmd(block.TransferCmd.tok); + continue; + } + List<Block> otherGotoCmdLabelTargets = new List<Block>(); + List<string> otherGotoCmdLabelNames = new List<string>(); + GotoCmd gotoCmd = block.TransferCmd as GotoCmd; + foreach (Block target in gotoCmd.labelTargets) + { + otherGotoCmdLabelTargets.Add(blockMap[target]); + otherGotoCmdLabelNames.Add(blockMap[target].Label); + } + blockMap[block].TransferCmd = new GotoCmd(block.TransferCmd.tok, otherGotoCmdLabelNames, otherGotoCmdLabelTargets); + } + return otherBlocks; + } + } + + public class SharedVariableInfo + { + public int introLayerNum; + public int hideLayerNum; + + public SharedVariableInfo(int introLayerNum, int hideLayerNum) + { + this.introLayerNum = introLayerNum; + this.hideLayerNum = hideLayerNum; + } + } + + public class LayerEraser : ReadOnlyVisitor + { + private QKeyValue RemoveLayerAttribute(QKeyValue iter) + { + if (iter == null) return null; + iter.Next = RemoveLayerAttribute(iter.Next); + return (iter.Key == "layer") ? iter.Next : iter; + } + + public override Variable VisitVariable(Variable node) + { + node.Attributes = RemoveLayerAttribute(node.Attributes); + return base.VisitVariable(node); + } + + public override Procedure VisitProcedure(Procedure node) + { + node.Attributes = RemoveLayerAttribute(node.Attributes); + return base.VisitProcedure(node); + } + + public override Implementation VisitImplementation(Implementation node) + { + node.Attributes = RemoveLayerAttribute(node.Attributes); + return base.VisitImplementation(node); + } + + public override Requires VisitRequires(Requires node) + { + node.Attributes = RemoveLayerAttribute(node.Attributes); + return base.VisitRequires(node); + } + + public override Ensures VisitEnsures(Ensures node) + { + node.Attributes = RemoveLayerAttribute(node.Attributes); + return base.VisitEnsures(node); + } + + public override Cmd VisitAssertCmd(AssertCmd node) + { + node.Attributes = RemoveLayerAttribute(node.Attributes); + return base.VisitAssertCmd(node); + } + } + + public class LayerRange + { + public int lowerLayerNum; + public int upperLayerNum; + public LayerRange(int layer) + { + this.lowerLayerNum = layer; + this.upperLayerNum = layer; + } + public LayerRange(int lower, int upper) + { + this.lowerLayerNum = lower; + this.upperLayerNum = upper; + } + public LayerRange(IEnumerable<int> layerNums) + { + int min = int.MaxValue; + int max = int.MinValue; + foreach (var layerNum in layerNums) + { + if (layerNum < min) + { + min = layerNum; + } + if (max < layerNum) + { + max = layerNum; + } + } + this.lowerLayerNum = min; + this.upperLayerNum = max; + } + public bool Contains(int layerNum) + { + return lowerLayerNum <= layerNum && layerNum <= upperLayerNum; + } + public bool Subset(int lower, int upper) + { + return lower <= lowerLayerNum && upperLayerNum <= upper; + } + public bool Equal(int lower, int upper) + { + return lower == lowerLayerNum && upperLayerNum == upper; + } + public bool Subset(LayerRange info) + { + return info.lowerLayerNum <= lowerLayerNum && upperLayerNum <= info.upperLayerNum; + } + } + + public class AtomicProcedureInfo + { + public bool isPure; + public LayerRange layerRange; + public AtomicProcedureInfo() + { + this.isPure = true; + this.layerRange = null; + } + public AtomicProcedureInfo(LayerRange layerRange) + { + this.isPure = false; + this.layerRange = layerRange; + } + } + + public class LocalVariableInfo + { + public int layer; + public LocalVariableInfo(int layer) + { + this.layer = layer; + } + } + + public class CivlTypeChecker : ReadOnlyVisitor + { + CheckingContext checkingContext; + Procedure enclosingProc; + Implementation enclosingImpl; + HashSet<Variable> sharedVarsAccessed; + int introducedLocalVarsUpperBound; + + public Program program; + public int errorCount; + public Dictionary<Variable, SharedVariableInfo> globalVarToSharedVarInfo; + public Dictionary<Procedure, ActionInfo> procToActionInfo; + public Dictionary<Procedure, AtomicProcedureInfo> procToAtomicProcedureInfo; + public Dictionary<Absy, HashSet<int>> absyToLayerNums; + public Dictionary<Variable, LocalVariableInfo> localVarToLocalVariableInfo; + Dictionary<CallCmd, int> pureCallLayer; + + public bool CallExists(CallCmd callCmd, int enclosingProcLayerNum, int layerNum) + { + Debug.Assert(procToAtomicProcedureInfo.ContainsKey(callCmd.Proc)); + var atomicProcedureInfo = procToAtomicProcedureInfo[callCmd.Proc]; + if (atomicProcedureInfo.isPure) + { + return pureCallLayer[callCmd] <= layerNum; + } + else + { + return enclosingProcLayerNum == layerNum; + } + } + + private static List<int> FindLayers(QKeyValue kv) + { + List<int> layers = new List<int>(); + for (; kv != null; kv = kv.Next) + { + if (kv.Key != "layer") continue; + foreach (var o in kv.Params) + { + Expr e = o as Expr; + if (e == null) return null; + LiteralExpr l = e as LiteralExpr; + if (l == null) return null; + if (!l.isBigNum) return null; + layers.Add(l.asBigNum.ToIntSafe); + } + } + return layers; + } + + private static int Least(IEnumerable<int> layerNums) + { + int least = int.MaxValue; + foreach (var layer in layerNums) + { + if (layer < least) + { + least = layer; + } + } + return least; + } + + private static MoverType GetMoverType(Ensures e) + { + if (QKeyValue.FindBoolAttribute(e.Attributes, "atomic")) + return MoverType.Atomic; + if (QKeyValue.FindBoolAttribute(e.Attributes, "right")) + return MoverType.Right; + if (QKeyValue.FindBoolAttribute(e.Attributes, "left")) + return MoverType.Left; + if (QKeyValue.FindBoolAttribute(e.Attributes, "both")) + return MoverType.Both; + return MoverType.Top; + } + + public CivlTypeChecker(Program program) + { + this.errorCount = 0; + this.checkingContext = new CheckingContext(null); + this.program = program; + this.enclosingProc = null; + this.enclosingImpl = null; + this.sharedVarsAccessed = null; + this.introducedLocalVarsUpperBound = int.MinValue; + + this.localVarToLocalVariableInfo = new Dictionary<Variable, LocalVariableInfo>(); + this.absyToLayerNums = new Dictionary<Absy, HashSet<int>>(); + this.globalVarToSharedVarInfo = new Dictionary<Variable, SharedVariableInfo>(); + this.procToActionInfo = new Dictionary<Procedure, ActionInfo>(); + this.procToAtomicProcedureInfo = new Dictionary<Procedure, AtomicProcedureInfo>(); + this.pureCallLayer = new Dictionary<CallCmd, int>(); + + foreach (var g in program.GlobalVariables) + { + List<int> layerNums = FindLayers(g.Attributes); + if (layerNums.Count == 0) + { + // Inaccessible from yielding and atomic procedures + } + else if (layerNums.Count == 1) + { + this.globalVarToSharedVarInfo[g] = new SharedVariableInfo(layerNums[0], int.MaxValue); + } + else if (layerNums.Count == 2) + { + this.globalVarToSharedVarInfo[g] = new SharedVariableInfo(layerNums[0], layerNums[1]); + } + else + { + Error(g, "Too many layer numbers"); + } + } + } + + private HashSet<int> allLayerNums; + public IEnumerable<int> AllLayerNums + { + get + { + if (allLayerNums == null) + { + allLayerNums = new HashSet<int>(); + foreach (ActionInfo actionInfo in procToActionInfo.Values) + { + allLayerNums.Add(actionInfo.createdAtLayerNum); + } + foreach (var layerNums in absyToLayerNums.Values) + { + foreach (var layer in layerNums) + { + allLayerNums.Add(layer); + } + } + } + return allLayerNums; + } + } + + private LayerRange FindLayerRange() + { + int maxIntroLayerNum = int.MinValue; + int minHideLayerNum = int.MaxValue; + foreach (var g in sharedVarsAccessed) + { + if (globalVarToSharedVarInfo[g].introLayerNum > maxIntroLayerNum) + { + maxIntroLayerNum = globalVarToSharedVarInfo[g].introLayerNum; + } + if (globalVarToSharedVarInfo[g].hideLayerNum < minHideLayerNum) + { + minHideLayerNum = globalVarToSharedVarInfo[g].hideLayerNum; + } + } + return new LayerRange(maxIntroLayerNum, minHideLayerNum); + } + + public void TypeCheck() + { + foreach (var proc in program.Procedures) + { + if (!QKeyValue.FindBoolAttribute(proc.Attributes, "pure")) continue; + if (QKeyValue.FindBoolAttribute(proc.Attributes, "yields")) + { + Error(proc, "Pure procedure must not yield"); + continue; + } + if (QKeyValue.FindBoolAttribute(proc.Attributes, "layer")) + { + Error(proc, "Pure procedure must not have layers"); + continue; + } + if (proc.Modifies.Count > 0) + { + Error(proc, "Pure procedure must not modify a global variable"); + continue; + } + procToAtomicProcedureInfo[proc] = new AtomicProcedureInfo(); + } + foreach (var proc in program.Procedures) + { + if (QKeyValue.FindBoolAttribute(proc.Attributes, "yields")) continue; + var procLayerNums = FindLayers(proc.Attributes); + if (procLayerNums.Count == 0) continue; + foreach (IdentifierExpr ie in proc.Modifies) + { + if (!globalVarToSharedVarInfo.ContainsKey(ie.Decl)) + { + Error(proc, "Atomic procedure cannot modify a global variable without layer numbers"); + continue; + } + } + int lower, upper; + if (procLayerNums.Count == 1) + { + lower = procLayerNums[0]; + upper = procLayerNums[0]; + } + else if (procLayerNums.Count == 2) + { + lower = procLayerNums[0]; + upper = procLayerNums[1]; + if (lower >= upper) + { + Error(proc, "Lower layer must be less than upper layer"); + continue; + } + } + else + { + Error(proc, "Atomic procedure must specify a layer range"); + continue; + } + LayerRange layerRange = new LayerRange(lower, upper); + procToAtomicProcedureInfo[proc] = new AtomicProcedureInfo(layerRange); + } + if (errorCount > 0) return; + + foreach (Implementation impl in program.Implementations) + { + if (!procToAtomicProcedureInfo.ContainsKey(impl.Proc)) continue; + var atomicProcedureInfo = procToAtomicProcedureInfo[impl.Proc]; + if (atomicProcedureInfo.isPure) + { + this.enclosingImpl = impl; + (new PurityChecker(this)).VisitImplementation(impl); + } + else + { + this.enclosingImpl = impl; + this.sharedVarsAccessed = new HashSet<Variable>(); + (new PurityChecker(this)).VisitImplementation(impl); + LayerRange upperBound = FindLayerRange(); + LayerRange lowerBound = atomicProcedureInfo.layerRange; + if (!lowerBound.Subset(upperBound)) + { + Error(impl, "Atomic procedure cannot access global variable"); + } + this.sharedVarsAccessed = null; + } + } + if (errorCount > 0) return; + + foreach (var proc in program.Procedures) + { + if (!QKeyValue.FindBoolAttribute(proc.Attributes, "yields")) continue; + + int createdAtLayerNum; // must be initialized by the following code, otherwise it is an error + int availableUptoLayerNum = int.MaxValue; + List<int> attrs = FindLayers(proc.Attributes); + if (attrs.Count == 1) + { + createdAtLayerNum = attrs[0]; + } + else if (attrs.Count == 2) + { + createdAtLayerNum = attrs[0]; + availableUptoLayerNum = attrs[1]; + } + else + { + Error(proc, "Incorrect number of layers"); + continue; + } + foreach (Ensures e in proc.Ensures) + { + MoverType moverType = GetMoverType(e); + if (moverType == MoverType.Top) continue; + CodeExpr codeExpr = e.Condition as CodeExpr; + if (codeExpr == null) + { + Error(e, "An atomic action must be a CodeExpr"); + continue; + } + if (procToActionInfo.ContainsKey(proc)) + { + Error(proc, "A procedure can have at most one atomic action"); + continue; + } + if (availableUptoLayerNum <= createdAtLayerNum) + { + Error(proc, "Creation layer number must be less than the available upto layer number"); + continue; + } + + sharedVarsAccessed = new HashSet<Variable>(); + enclosingProc = proc; + enclosingImpl = null; + base.VisitEnsures(e); + LayerRange upperBound = FindLayerRange(); + LayerRange lowerBound = new LayerRange(createdAtLayerNum, availableUptoLayerNum); + if (lowerBound.Subset(upperBound)) + { + procToActionInfo[proc] = new AtomicActionInfo(proc, e, moverType, createdAtLayerNum, availableUptoLayerNum); + } + else + { + Error(e, "A variable being accessed in this action is unavailable"); + } + sharedVarsAccessed = null; + } + if (errorCount > 0) continue; + if (!procToActionInfo.ContainsKey(proc)) + { + if (availableUptoLayerNum < createdAtLayerNum) + { + Error(proc, "Creation layer number must be no more than the available upto layer number"); + continue; + } + else + { + procToActionInfo[proc] = new ActionInfo(proc, createdAtLayerNum, availableUptoLayerNum); + } + } + } + if (errorCount > 0) return; + + foreach (var impl in program.Implementations) + { + if (!procToActionInfo.ContainsKey(impl.Proc)) continue; + ActionInfo actionInfo = procToActionInfo[impl.Proc]; + procToActionInfo[impl.Proc].hasImplementation = true; + if (actionInfo.isExtern) + { + Error(impl.Proc, "Extern procedure cannot have an implementation"); + } + } + if (errorCount > 0) return; + + foreach (Procedure proc in procToActionInfo.Keys) + { + for (int i = 0; i < proc.InParams.Count; i++) + { + Variable v = proc.InParams[i]; + var layer = FindLocalVariableLayer(proc, v, procToActionInfo[proc].createdAtLayerNum); + if (layer == int.MinValue) continue; + localVarToLocalVariableInfo[v] = new LocalVariableInfo(layer); + } + for (int i = 0; i < proc.OutParams.Count; i++) + { + Variable v = proc.OutParams[i]; + var layer = FindLocalVariableLayer(proc, v, procToActionInfo[proc].createdAtLayerNum); + if (layer == int.MinValue) continue; + localVarToLocalVariableInfo[v] = new LocalVariableInfo(layer); + } + } + foreach (Implementation node in program.Implementations) + { + if (!procToActionInfo.ContainsKey(node.Proc)) continue; + foreach (Variable v in node.LocVars) + { + var layer = FindLocalVariableLayer(node, v, procToActionInfo[node.Proc].createdAtLayerNum); + if (layer == int.MinValue) continue; + localVarToLocalVariableInfo[v] = new LocalVariableInfo(layer); + } + for (int i = 0; i < node.Proc.InParams.Count; i++) + { + Variable v = node.Proc.InParams[i]; + if (!localVarToLocalVariableInfo.ContainsKey(v)) continue; + var layer = localVarToLocalVariableInfo[v].layer; + localVarToLocalVariableInfo[node.InParams[i]] = new LocalVariableInfo(layer); + } + for (int i = 0; i < node.Proc.OutParams.Count; i++) + { + Variable v = node.Proc.OutParams[i]; + if (!localVarToLocalVariableInfo.ContainsKey(v)) continue; + var layer = localVarToLocalVariableInfo[v].layer; + localVarToLocalVariableInfo[node.OutParams[i]] = new LocalVariableInfo(layer); + } + } + if (errorCount > 0) return; + + this.VisitProgram(program); + if (errorCount > 0) return; + YieldTypeChecker.PerformYieldSafeCheck(this); + new LayerEraser().VisitProgram(program); + } + + public IEnumerable<Variable> SharedVariables + { + get { return this.globalVarToSharedVarInfo.Keys; } + } + + private int FindLocalVariableLayer(Declaration decl, Variable v, int enclosingProcLayerNum) + { + var layers = FindLayers(v.Attributes); + if (layers.Count == 0) return int.MinValue; + if (layers.Count > 1) + { + Error(decl, "Incorrect number of layers"); + return int.MinValue; + } + if (layers[0] > enclosingProcLayerNum) + { + Error(decl, "Layer of local variable cannot be greater than the creation layer of enclosing procedure"); + return int.MinValue; + } + return layers[0]; + } + + public override Implementation VisitImplementation(Implementation node) + { + if (!procToActionInfo.ContainsKey(node.Proc)) + { + return node; + } + this.enclosingImpl = node; + this.enclosingProc = null; + return base.VisitImplementation(node); + } + + public override Procedure VisitProcedure(Procedure node) + { + if (!procToActionInfo.ContainsKey(node)) + { + return node; + } + this.enclosingProc = node; + this.enclosingImpl = null; + return base.VisitProcedure(node); + } + + public override Cmd VisitCallCmd(CallCmd node) + { + int enclosingProcLayerNum = procToActionInfo[enclosingImpl.Proc].createdAtLayerNum; + if (procToActionInfo.ContainsKey(node.Proc)) + { + ActionInfo actionInfo = procToActionInfo[node.Proc]; + if (node.IsAsync && actionInfo is AtomicActionInfo) + { + Error(node, "Target of async call cannot be an atomic action"); + } + int calleeLayerNum = procToActionInfo[node.Proc].createdAtLayerNum; + if (enclosingProcLayerNum < calleeLayerNum || + (enclosingProcLayerNum == calleeLayerNum && actionInfo is AtomicActionInfo)) + { + Error(node, "The layer of the caller must be greater than the layer of the callee"); + } + else if (enclosingProcLayerNum == calleeLayerNum && enclosingImpl.OutParams.Count > 0) + { + HashSet<Variable> outParams = new HashSet<Variable>(enclosingImpl.OutParams); + foreach (var x in node.Outs) + { + if (x.Decl is GlobalVariable) + { + Error(node, "A global variable cannot be used as output argument for this call"); + } + else if (outParams.Contains(x.Decl)) + { + Error(node, "An output variable of the enclosing implementation cannot be used as output argument for this call"); + } + } + } + if (actionInfo.availableUptoLayerNum < enclosingProcLayerNum) + { + Error(node, "The callee is not available in the caller procedure"); + } + for (int i = 0; i < node.Ins.Count; i++) + { + Visit(node.Ins[i]); + if (introducedLocalVarsUpperBound != int.MinValue) + { + var formal = node.Proc.InParams[i]; + if (!localVarToLocalVariableInfo.ContainsKey(formal) || + introducedLocalVarsUpperBound > localVarToLocalVariableInfo[formal].layer) + { + Error(node, "An introduced local variable is accessed but not available"); + } + introducedLocalVarsUpperBound = int.MinValue; + } + } + for (int i = 0; i < node.Outs.Count; i++) + { + var formal = node.Proc.OutParams[i]; + if (!localVarToLocalVariableInfo.ContainsKey(formal)) continue; + var actual = node.Outs[i].Decl; + if (localVarToLocalVariableInfo.ContainsKey(actual) && + localVarToLocalVariableInfo[formal].layer <= localVarToLocalVariableInfo[actual].layer) + continue; + Error(node, "Formal parameter of call must be introduced no later than the actual parameter"); + } + return node; + } + else if (procToAtomicProcedureInfo.ContainsKey(node.Proc)) + { + var atomicProcedureInfo = procToAtomicProcedureInfo[node.Proc]; + if (atomicProcedureInfo.isPure) + { + if (node.Outs.Count > 0) + { + int inferredLayer = int.MinValue; + foreach (var ie in node.Outs) + { + if (!localVarToLocalVariableInfo.ContainsKey(ie.Decl)) continue; + if (inferredLayer < localVarToLocalVariableInfo[ie.Decl].layer) + { + inferredLayer = localVarToLocalVariableInfo[ie.Decl].layer; + } + } + pureCallLayer[node] = inferredLayer; + if (inferredLayer != int.MinValue) + { + foreach (var ie in node.Outs) + { + if (!localVarToLocalVariableInfo.ContainsKey(ie.Decl)) + { + Error(node, "Output variable must be introduced"); + } + else if (inferredLayer != localVarToLocalVariableInfo[ie.Decl].layer) + { + Error(node, "All output variables must be introduced at the same layer"); + } + } + } + Debug.Assert(introducedLocalVarsUpperBound == int.MinValue); + foreach (var e in node.Ins) + { + Visit(e); + if (inferredLayer < introducedLocalVarsUpperBound) + { + Error(node, "An introduced local variable is not accessible"); + } + introducedLocalVarsUpperBound = int.MinValue; + } + } + else + { + Debug.Assert(introducedLocalVarsUpperBound == int.MinValue); + int inferredLayer = int.MinValue; + foreach (var e in node.Ins) + { + Visit(e); + if (inferredLayer < introducedLocalVarsUpperBound) + { + inferredLayer = introducedLocalVarsUpperBound; + } + introducedLocalVarsUpperBound = int.MinValue; + } + pureCallLayer[node] = inferredLayer; + } + } + else + { + if (enclosingProcLayerNum != atomicProcedureInfo.layerRange.upperLayerNum) + { + Error(node, "Creation layer of caller must be the upper bound of the layer range of callee"); + } + foreach (var ie in node.Proc.Modifies) + { + if (enclosingProcLayerNum != globalVarToSharedVarInfo[ie.Decl].introLayerNum) + { + Error(node, "Creation layer of caller must be identical to the introduction layer of modified variable"); + } + } + foreach (var ie in node.Outs) + { + if (localVarToLocalVariableInfo.ContainsKey(ie.Decl) && + enclosingProcLayerNum == localVarToLocalVariableInfo[ie.Decl].layer) + continue; + Error(node, "Output variable must be introduced at the creation layer of caller"); + } + } + return node; + } + else + { + Error(node, "A yielding procedure can call only atomic or yielding procedures"); + return node; + } + } + + public override Cmd VisitParCallCmd(ParCallCmd node) + { + int enclosingProcLayerNum = procToActionInfo[enclosingImpl.Proc].createdAtLayerNum; + bool isLeftMover = true; + bool isRightMover = true; + int maxCalleeLayerNum = 0; + int atomicActionCalleeLayerNum = 0; + int numAtomicActions = 0; + foreach (CallCmd iter in node.CallCmds) + { + ActionInfo actionInfo = procToActionInfo[iter.Proc]; + isLeftMover = isLeftMover && actionInfo.IsLeftMover; + isRightMover = isRightMover && actionInfo.IsRightMover; + if (actionInfo.createdAtLayerNum > maxCalleeLayerNum) + { + maxCalleeLayerNum = actionInfo.createdAtLayerNum; + } + if (actionInfo is AtomicActionInfo) + { + numAtomicActions++; + if (atomicActionCalleeLayerNum == 0) + { + atomicActionCalleeLayerNum = actionInfo.createdAtLayerNum; + } + else if (atomicActionCalleeLayerNum != actionInfo.createdAtLayerNum) + { + Error(node, "All atomic actions must be introduced at the same layer"); + } + } + } + if (numAtomicActions > 1 && !isLeftMover && !isRightMover) + { + Error(node, "The atomic actions in the parallel call must be all right movers or all left movers"); + } + if (0 < atomicActionCalleeLayerNum && atomicActionCalleeLayerNum < maxCalleeLayerNum) + { + Error(node, "Atomic actions must be introduced at the highest layer"); + } + return base.VisitParCallCmd(node); + } + + public override Expr VisitIdentifierExpr(IdentifierExpr node) + { + if (node.Decl is GlobalVariable) + { + if (sharedVarsAccessed == null) + { + Error(node, "Shared variable can be accessed only in atomic actions or specifications"); + } + else if (this.globalVarToSharedVarInfo.ContainsKey(node.Decl)) + { + sharedVarsAccessed.Add(node.Decl); + } + else + { + Error(node, "Accessed shared variable must have layer annotation"); + } + } + else if ((node.Decl is Formal || node.Decl is Variable) && localVarToLocalVariableInfo.ContainsKey(node.Decl)) + { + var localVariableInfo = localVarToLocalVariableInfo[node.Decl]; + if (introducedLocalVarsUpperBound < localVariableInfo.layer) + { + introducedLocalVarsUpperBound = localVariableInfo.layer; + } + } + return base.VisitIdentifierExpr(node); + } + + public override Ensures VisitEnsures(Ensures ensures) + { + ActionInfo actionInfo = procToActionInfo[enclosingProc]; + AtomicActionInfo atomicActionInfo = actionInfo as AtomicActionInfo; + if (atomicActionInfo != null && atomicActionInfo.ensures == ensures) + { + // This case has already been checked + } + else + { + sharedVarsAccessed = new HashSet<Variable>(); + Debug.Assert(introducedLocalVarsUpperBound == int.MinValue); + base.VisitEnsures(ensures); + CheckAndAddLayers(ensures, ensures.Attributes, actionInfo.createdAtLayerNum); + if (introducedLocalVarsUpperBound > Least(FindLayers(ensures.Attributes))) + { + Error(ensures, "An introduced local variable is accessed but not available"); + } + introducedLocalVarsUpperBound = int.MinValue; + sharedVarsAccessed = null; + } + return ensures; + } + + public override Requires VisitRequires(Requires requires) + { + sharedVarsAccessed = new HashSet<Variable>(); + Debug.Assert(introducedLocalVarsUpperBound == int.MinValue); + base.VisitRequires(requires); + CheckAndAddLayers(requires, requires.Attributes, procToActionInfo[enclosingProc].createdAtLayerNum); + if (introducedLocalVarsUpperBound > Least(FindLayers(requires.Attributes))) + { + Error(requires, "An introduced local variable is accessed but not available"); + } + introducedLocalVarsUpperBound = int.MinValue; + sharedVarsAccessed = null; + return requires; + } + + public override Cmd VisitAssertCmd(AssertCmd node) + { + if (enclosingImpl == null) + { + // in this case, we are visiting an assert inside a CodeExpr + return base.VisitAssertCmd(node); + } + sharedVarsAccessed = new HashSet<Variable>(); + Debug.Assert(introducedLocalVarsUpperBound == int.MinValue); + base.VisitAssertCmd(node); + CheckAndAddLayers(node, node.Attributes, procToActionInfo[enclosingImpl.Proc].createdAtLayerNum); + if (introducedLocalVarsUpperBound > Least(FindLayers(node.Attributes))) + { + Error(node, "An introduced local variable is accessed but not available"); + } + introducedLocalVarsUpperBound = int.MinValue; + sharedVarsAccessed = null; + return node; + } + + private List<int> RemoveDuplicatesAndSort(List<int> attrs) + { + HashSet<int> layerSet = new HashSet<int>(attrs); + List<int> layers = new List<int>(layerSet); + layers.Sort(); + return layers; + } + + private void CheckAndAddLayers(Absy node, QKeyValue attributes, int enclosingProcLayerNum) + { + List<int> attrs = RemoveDuplicatesAndSort(FindLayers(attributes)); + if (attrs.Count == 0) + { + Error(node, "layer not present"); + return; + } + LayerRange upperBound = FindLayerRange(); + absyToLayerNums[node] = new HashSet<int>(); + foreach (int layerNum in attrs) + { + if (layerNum > enclosingProcLayerNum) + { + Error(node, "The layer cannot be greater than the layer of enclosing procedure"); + } + else if (upperBound.Contains(layerNum)) + { + absyToLayerNums[node].Add(layerNum); + } + else + { + Error(node, string.Format("A variable being accessed in this specification is unavailable at layer {0}", layerNum)); + } + } + } + + public void Error(Absy node, string message) + { + checkingContext.Error(node, message); + errorCount++; + } + + private class PurityChecker : StandardVisitor + { + private CivlTypeChecker civlTypeChecker; + + public PurityChecker(CivlTypeChecker civlTypeChecker) + { + this.civlTypeChecker = civlTypeChecker; + } + + public override Cmd VisitCallCmd(CallCmd node) + { + Procedure enclosingProc = civlTypeChecker.enclosingImpl.Proc; + if (!civlTypeChecker.procToAtomicProcedureInfo.ContainsKey(node.Proc)) + { + civlTypeChecker.Error(node, "Atomic procedure can only call an atomic procedure"); + return base.VisitCallCmd(node); + } + var callerInfo = civlTypeChecker.procToAtomicProcedureInfo[enclosingProc]; + var calleeInfo = civlTypeChecker.procToAtomicProcedureInfo[node.Proc]; + if (calleeInfo.isPure) + { + // do nothing + } + else if (callerInfo.isPure) + { + civlTypeChecker.Error(node, "Pure procedure can only call pure procedures"); + } + else if (!callerInfo.layerRange.Subset(calleeInfo.layerRange)) + { + civlTypeChecker.Error(node, "Caller layers must be subset of callee layers"); + } + return base.VisitCallCmd(node); + } + + public override Cmd VisitParCallCmd(ParCallCmd node) + { + civlTypeChecker.Error(node, "Atomic procedures cannot make parallel calls"); + return node; + } + + public override Expr VisitIdentifierExpr(IdentifierExpr node) + { + Procedure enclosingProc = civlTypeChecker.enclosingImpl.Proc; + if (node.Decl is GlobalVariable) + { + if (civlTypeChecker.procToAtomicProcedureInfo[enclosingProc].isPure) + { + civlTypeChecker.Error(node, "Pure procedure cannot access global variables"); + } + else if (!civlTypeChecker.globalVarToSharedVarInfo.ContainsKey(node.Decl)) + { + civlTypeChecker.Error(node, "Atomic procedure cannot access a global variable without layer numbers"); + } + else + { + civlTypeChecker.sharedVarsAccessed.Add(node.Decl); + } + } + return node; + } + } + } +} diff --git a/Source/Concurrency/Concurrency.csproj b/Source/Concurrency/Concurrency.csproj index c245d05a..ac90077c 100644 --- a/Source/Concurrency/Concurrency.csproj +++ b/Source/Concurrency/Concurrency.csproj @@ -1,115 +1,115 @@ -<?xml version="1.0" encoding="utf-8"?>
-<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
- <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
- <PropertyGroup>
- <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
- <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
- <ProjectGuid>{D07B8E38-E172-47F4-AD02-0373014A46D3}</ProjectGuid>
- <OutputType>Library</OutputType>
- <AppDesignerFolder>Properties</AppDesignerFolder>
- <RootNamespace>Concurrency</RootNamespace>
- <AssemblyName>Concurrency</AssemblyName>
- <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
- <FileAlignment>512</FileAlignment>
- <TargetFrameworkProfile Condition=" '$(OS)' == 'Windows_NT'">Client</TargetFrameworkProfile>
- </PropertyGroup>
- <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
- <PlatformTarget>AnyCPU</PlatformTarget>
- <DebugSymbols>true</DebugSymbols>
- <DebugType>full</DebugType>
- <Optimize>false</Optimize>
- <OutputPath>bin\Debug\</OutputPath>
- <DefineConstants>TRACE;DEBUG</DefineConstants>
- <ErrorReport>prompt</ErrorReport>
- <WarningLevel>4</WarningLevel>
- </PropertyGroup>
- <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
- <PlatformTarget>AnyCPU</PlatformTarget>
- <DebugType>pdbonly</DebugType>
- <Optimize>true</Optimize>
- <OutputPath>bin\Release\</OutputPath>
- <DefineConstants>TRACE</DefineConstants>
- <ErrorReport>prompt</ErrorReport>
- <WarningLevel>4</WarningLevel>
- </PropertyGroup>
- <PropertyGroup>
- <StartupObject />
- </PropertyGroup>
- <PropertyGroup>
- <SignAssembly>true</SignAssembly>
- </PropertyGroup>
- <PropertyGroup>
- <AssemblyOriginatorKeyFile>..\InterimKey.snk</AssemblyOriginatorKeyFile>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'QED|AnyCPU'">
- <DebugSymbols>true</DebugSymbols>
- <OutputPath>bin\QED\</OutputPath>
- <DefineConstants>TRACE;DEBUG;QED</DefineConstants>
- <DebugType>full</DebugType>
- <PlatformTarget>AnyCPU</PlatformTarget>
- <ErrorReport>prompt</ErrorReport>
- <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
- </PropertyGroup>
- <Choose>
- <When Condition="'$(Configuration)' == 'QED'">
- <ItemGroup>
- <Reference Include="Microsoft.Automata">
- <HintPath>..\..\Binaries\Microsoft.Automata.dll</HintPath>
- </Reference>
- </ItemGroup>
- </When>
- <Otherwise>
- </Otherwise>
- </Choose>
- <ItemGroup>
- <Reference Include="System" />
- <Reference Include="System.Core" />
- <Reference Include="System.Xml.Linq" />
- <Reference Include="System.Data.DataSetExtensions" />
- <Reference Include="Microsoft.CSharp" />
- <Reference Include="System.Data" />
- <Reference Include="System.Xml" />
- </ItemGroup>
- <ItemGroup>
- <Compile Include="LinearSets.cs" />
- <Compile Include="MoverCheck.cs" />
- <Compile Include="OwickiGries.cs" />
- <Compile Include="Program.cs" />
- <Compile Include="Properties\AssemblyInfo.cs" />
- <Compile Include="SimulationRelation.cs" />
- <Compile Include="TypeCheck.cs" />
- <Compile Include="YieldTypeChecker.cs" />
- </ItemGroup>
- <ItemGroup>
- <None Include="App.config" />
- </ItemGroup>
- <ItemGroup>
- <ProjectReference Include="..\Basetypes\Basetypes.csproj">
- <Project>{43dfad18-3e35-4558-9be2-caff6b5ba8a0}</Project>
- <Name>Basetypes</Name>
- </ProjectReference>
- <ProjectReference Include="..\Core\Core.csproj">
- <Project>{b230a69c-c466-4065-b9c1-84d80e76d802}</Project>
- <Name>Core</Name>
- </ProjectReference>
- <ProjectReference Include="..\Graph\Graph.csproj">
- <Project>{69a2b0b8-bcac-4101-ae7a-556fcc58c06e}</Project>
- <Name>Graph</Name>
- </ProjectReference>
- <ProjectReference Include="..\ParserHelper\ParserHelper.csproj">
- <Project>{fcd3ac7f-9dfd-46c8-ab1e-09f0b0f16dc5}</Project>
- <Name>ParserHelper</Name>
- </ProjectReference>
- </ItemGroup>
- <ItemGroup>
- <WCFMetadata Include="Service References\" />
- </ItemGroup>
- <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
- <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
- Other similar extension points exist, see Microsoft.Common.targets.
- <Target Name="BeforeBuild">
- </Target>
- <Target Name="AfterBuild">
- </Target>
- -->
+<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" /> + <PropertyGroup> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> + <ProjectGuid>{D07B8E38-E172-47F4-AD02-0373014A46D3}</ProjectGuid> + <OutputType>Library</OutputType> + <AppDesignerFolder>Properties</AppDesignerFolder> + <RootNamespace>Concurrency</RootNamespace> + <AssemblyName>BoogieConcurrency</AssemblyName> + <TargetFrameworkVersion>v4.0</TargetFrameworkVersion> + <FileAlignment>512</FileAlignment> + <TargetFrameworkProfile Condition=" '$(OS)' == 'Windows_NT'">Client</TargetFrameworkProfile> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> + <PlatformTarget>AnyCPU</PlatformTarget> + <DebugSymbols>true</DebugSymbols> + <DebugType>full</DebugType> + <Optimize>false</Optimize> + <OutputPath>bin\Debug\</OutputPath> + <DefineConstants>TRACE;DEBUG</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> + <PlatformTarget>AnyCPU</PlatformTarget> + <DebugType>pdbonly</DebugType> + <Optimize>true</Optimize> + <OutputPath>bin\Release\</OutputPath> + <DefineConstants>TRACE</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + </PropertyGroup> + <PropertyGroup> + <StartupObject /> + </PropertyGroup> + <PropertyGroup> + <SignAssembly>true</SignAssembly> + </PropertyGroup> + <PropertyGroup> + <AssemblyOriginatorKeyFile>..\InterimKey.snk</AssemblyOriginatorKeyFile> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'QED|AnyCPU'"> + <DebugSymbols>true</DebugSymbols> + <OutputPath>bin\QED\</OutputPath> + <DefineConstants>TRACE;DEBUG;QED</DefineConstants> + <DebugType>full</DebugType> + <PlatformTarget>AnyCPU</PlatformTarget> + <ErrorReport>prompt</ErrorReport> + <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet> + </PropertyGroup> + <Choose> + <When Condition="'$(Configuration)' == 'QED'"> + <ItemGroup> + <Reference Include="Microsoft.Automata"> + <HintPath>..\..\Binaries\Microsoft.Automata.dll</HintPath> + </Reference> + </ItemGroup> + </When> + <Otherwise> + </Otherwise> + </Choose> + <ItemGroup> + <Reference Include="System" /> + <Reference Include="System.Core" /> + <Reference Include="System.Xml.Linq" /> + <Reference Include="System.Data.DataSetExtensions" /> + <Reference Include="Microsoft.CSharp" /> + <Reference Include="System.Data" /> + <Reference Include="System.Xml" /> + </ItemGroup> + <ItemGroup> + <Compile Include="LinearSets.cs" /> + <Compile Include="MoverCheck.cs" /> + <Compile Include="CivlRefinement.cs" /> + <Compile Include="Program.cs" /> + <Compile Include="Properties\AssemblyInfo.cs" /> + <Compile Include="SimulationRelation.cs" /> + <Compile Include="CivlTypeChecker.cs" /> + <Compile Include="YieldTypeChecker.cs" /> + </ItemGroup> + <ItemGroup> + <None Include="App.config" /> + </ItemGroup> + <ItemGroup> + <ProjectReference Include="..\Basetypes\Basetypes.csproj"> + <Project>{43dfad18-3e35-4558-9be2-caff6b5ba8a0}</Project> + <Name>Basetypes</Name> + </ProjectReference> + <ProjectReference Include="..\Core\Core.csproj"> + <Project>{b230a69c-c466-4065-b9c1-84d80e76d802}</Project> + <Name>Core</Name> + </ProjectReference> + <ProjectReference Include="..\Graph\Graph.csproj"> + <Project>{69a2b0b8-bcac-4101-ae7a-556fcc58c06e}</Project> + <Name>Graph</Name> + </ProjectReference> + <ProjectReference Include="..\ParserHelper\ParserHelper.csproj"> + <Project>{fcd3ac7f-9dfd-46c8-ab1e-09f0b0f16dc5}</Project> + <Name>ParserHelper</Name> + </ProjectReference> + </ItemGroup> + <ItemGroup> + <WCFMetadata Include="Service References\" /> + </ItemGroup> + <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> + <!-- To modify your build process, add your task inside one of the targets below and uncomment it. + Other similar extension points exist, see Microsoft.Common.targets. + <Target Name="BeforeBuild"> + </Target> + <Target Name="AfterBuild"> + </Target> + --> </Project>
\ No newline at end of file diff --git a/Source/Concurrency/LinearSets.cs b/Source/Concurrency/LinearSets.cs index e3891c18..f654b688 100644 --- a/Source/Concurrency/LinearSets.cs +++ b/Source/Concurrency/LinearSets.cs @@ -1,1004 +1,1003 @@ -using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using Microsoft.Boogie;
-using System.Diagnostics;
-
-namespace Microsoft.Boogie
-{
- public class LinearEraser : ReadOnlyVisitor
- {
- private QKeyValue RemoveLinearAttribute(QKeyValue iter)
- {
- if (iter == null) return null;
- iter.Next = RemoveLinearAttribute(iter.Next);
- return (iter.Key == "linear" || iter.Key == "linear_in" || iter.Key == "linear_out") ? iter.Next : iter;
- }
-
- public override Variable VisitVariable(Variable node)
- {
- node.Attributes = RemoveLinearAttribute(node.Attributes);
- return base.VisitVariable(node);
- }
-
- public override Function VisitFunction(Function node)
- {
- node.Attributes = RemoveLinearAttribute(node.Attributes);
- return base.VisitFunction(node);
- }
- }
-
- public enum LinearKind {
- LINEAR,
- LINEAR_IN,
- LINEAR_OUT
- }
-
- public class LinearTypeChecker : ReadOnlyVisitor
- {
- public Program program;
- public int errorCount;
- public CheckingContext checkingContext;
- public Dictionary<string, Dictionary<Type, Function>> domainNameToCollectors;
- private Dictionary<Absy, HashSet<Variable>> availableLinearVars;
- public Dictionary<Variable, LinearQualifier> inParamToLinearQualifier;
- public Dictionary<Variable, string> outParamToDomainName;
- public Dictionary<Variable, string> varToDomainName;
- public Dictionary<Variable, string> globalVarToDomainName;
- public Dictionary<string, LinearDomain> linearDomains;
-
- public LinearTypeChecker(Program program)
- {
- this.program = program;
- this.errorCount = 0;
- this.checkingContext = new CheckingContext(null);
- this.domainNameToCollectors = new Dictionary<string, Dictionary<Type, Function>>();
- this.availableLinearVars = new Dictionary<Absy, HashSet<Variable>>();
- this.inParamToLinearQualifier = new Dictionary<Variable, LinearQualifier>();
- this.outParamToDomainName = new Dictionary<Variable, string>();
- this.varToDomainName = new Dictionary<Variable, string>();
- this.globalVarToDomainName = new Dictionary<Variable, string>();
- this.linearDomains = new Dictionary<string, LinearDomain>();
- }
- public void TypeCheck()
- {
- this.VisitProgram(program);
- foreach (string domainName in domainNameToCollectors.Keys)
- {
- var collectors = domainNameToCollectors[domainName];
- if (collectors.Count == 0) continue;
- this.linearDomains[domainName] = new LinearDomain(program, domainName, collectors);
- }
- Dictionary<Absy, HashSet<Variable>> newAvailableLinearVars = new Dictionary<Absy, HashSet<Variable>>();
- foreach (Absy absy in this.availableLinearVars.Keys)
- {
- HashSet<Variable> vars = new HashSet<Variable>();
- foreach (Variable var in this.availableLinearVars[absy])
- {
- if (var is GlobalVariable) continue;
- string domainName = FindDomainName(var);
- if (this.linearDomains.ContainsKey(domainName))
- {
- vars.Add(var);
- }
- }
- newAvailableLinearVars[absy] = vars;
- }
- this.availableLinearVars = newAvailableLinearVars;
- var temp = new Dictionary<Variable, string>();
- foreach (Variable v in outParamToDomainName.Keys)
- {
- if (linearDomains.ContainsKey(outParamToDomainName[v]))
- temp[v] = outParamToDomainName[v];
- }
- this.outParamToDomainName = temp;
- temp = new Dictionary<Variable, string>();
- foreach (Variable v in varToDomainName.Keys)
- {
- if (linearDomains.ContainsKey(varToDomainName[v]))
- temp[v] = varToDomainName[v];
- }
- this.varToDomainName = temp;
- temp = new Dictionary<Variable, string>();
- foreach (Variable v in globalVarToDomainName.Keys)
- {
- if (linearDomains.ContainsKey(globalVarToDomainName[v]))
- temp[v] = globalVarToDomainName[v];
- }
- this.globalVarToDomainName = temp;
- }
- private void Error(Absy node, string message)
- {
- checkingContext.Error(node, message);
- errorCount++;
- }
- public override Program VisitProgram(Program node)
- {
- foreach (GlobalVariable g in program.GlobalVariables)
- {
- string domainName = FindDomainName(g);
- if (domainName != null)
- {
- globalVarToDomainName[g] = domainName;
- }
- }
- return base.VisitProgram(node);
- }
- public override Function VisitFunction(Function node)
- {
- string domainName = QKeyValue.FindStringAttribute(node.Attributes, "linear");
- if (domainName != null)
- {
- if (!domainNameToCollectors.ContainsKey(domainName))
- {
- domainNameToCollectors[domainName] = new Dictionary<Type, Function>();
- }
- if (node.InParams.Count == 1 && node.OutParams.Count == 1)
- {
- Type inType = node.InParams[0].TypedIdent.Type;
- MapType outType = node.OutParams[0].TypedIdent.Type as MapType;
- if (domainNameToCollectors[domainName].ContainsKey(inType))
- {
- Error(node, string.Format("A collector for domain for input type has already been defined"));
- }
- else if (outType == null || outType.Arguments.Count != 1 || !outType.Result.Equals(Type.Bool))
- {
- Error(node, "Output of a linear domain collector should be of set type");
- }
- else
- {
- domainNameToCollectors[domainName][inType] = node;
- }
- }
- else
- {
- Error(node, "Linear domain collector should have one input and one output parameter");
- }
- }
- return base.VisitFunction(node);
- }
- public override Implementation VisitImplementation(Implementation node)
- {
- node.PruneUnreachableBlocks();
- node.ComputePredecessorsForBlocks();
- GraphUtil.Graph<Block> graph = Program.GraphFromImpl(node);
- graph.ComputeLoops();
-
- HashSet<Variable> start = new HashSet<Variable>(globalVarToDomainName.Keys);
- for (int i = 0; i < node.InParams.Count; i++)
- {
- Variable v = node.Proc.InParams[i];
- string domainName = FindDomainName(v);
- if (domainName != null)
- {
- var kind = FindLinearKind(v);
- inParamToLinearQualifier[node.InParams[i]] = new LinearQualifier(domainName, kind);
- if (kind == LinearKind.LINEAR || kind == LinearKind.LINEAR_IN)
- {
- start.Add(node.InParams[i]);
- }
- }
- }
- for (int i = 0; i < node.OutParams.Count; i++)
- {
- string domainName = FindDomainName(node.Proc.OutParams[i]);
- if (domainName != null)
- {
- outParamToDomainName[node.OutParams[i]] = domainName;
- }
- }
-
- var oldErrorCount = this.errorCount;
- var impl = base.VisitImplementation(node);
- if (oldErrorCount < this.errorCount)
- return impl;
-
- Stack<Block> dfsStack = new Stack<Block>();
- HashSet<Block> dfsStackAsSet = new HashSet<Block>();
- availableLinearVars[node.Blocks[0]] = start;
- dfsStack.Push(node.Blocks[0]);
- dfsStackAsSet.Add(node.Blocks[0]);
- while (dfsStack.Count > 0)
- {
- Block b = dfsStack.Pop();
- dfsStackAsSet.Remove(b);
- HashSet<Variable> end = PropagateAvailableLinearVarsAcrossBlock(b);
- if (b.TransferCmd is ReturnCmd)
- {
- foreach (GlobalVariable g in globalVarToDomainName.Keys.Except(end))
- {
- Error(b.TransferCmd, string.Format("Global variable {0} must be available at a return", g.Name));
- }
- foreach (Variable v in node.InParams)
- {
- if (FindDomainName(v) == null || FindLinearKind(v) == LinearKind.LINEAR_IN || end.Contains(v)) continue;
- Error(b.TransferCmd, string.Format("Input variable {0} must be available at a return", v.Name));
- }
- foreach (Variable v in node.OutParams)
- {
- if (FindDomainName(v) == null || end.Contains(v)) continue;
- Error(b.TransferCmd, string.Format("Output variable {0} must be available at a return", v.Name));
- }
- continue;
- }
- GotoCmd gotoCmd = b.TransferCmd as GotoCmd;
- foreach (Block target in gotoCmd.labelTargets)
- {
- if (!availableLinearVars.ContainsKey(target))
- {
- availableLinearVars[target] = new HashSet<Variable>(end);
- dfsStack.Push(target);
- dfsStackAsSet.Add(target);
- }
- else
- {
- var savedAvailableVars = new HashSet<Variable>(availableLinearVars[target]);
- availableLinearVars[target].IntersectWith(end);
- if (savedAvailableVars.IsProperSupersetOf(availableLinearVars[target]) && !dfsStackAsSet.Contains(target))
- {
- dfsStack.Push(target);
- dfsStackAsSet.Add(target);
- }
- }
- }
- }
-
- if (graph.Reducible)
- {
- foreach (Block header in graph.Headers)
- {
- foreach (GlobalVariable g in globalVarToDomainName.Keys.Except(availableLinearVars[header]))
- {
- Error(header, string.Format("Global variable {0} must be available at a loop head", g.Name));
- }
- }
- }
- return impl;
- }
- public void AddAvailableVars(CallCmd callCmd, HashSet<Variable> start)
- {
- foreach (IdentifierExpr ie in callCmd.Outs)
- {
- if (FindDomainName(ie.Decl) == null) continue;
- start.Add(ie.Decl);
- }
- for (int i = 0; i < callCmd.Proc.InParams.Count; i++)
- {
- IdentifierExpr ie = callCmd.Ins[i] as IdentifierExpr;
- if (ie == null) continue;
- Variable v = callCmd.Proc.InParams[i];
- if (FindDomainName(v) == null) continue;
- if (FindLinearKind(v) == LinearKind.LINEAR_OUT)
- {
- start.Add(ie.Decl);
- }
- }
- }
- public void AddAvailableVars(ParCallCmd parCallCmd, HashSet<Variable> start)
- {
- foreach (CallCmd callCmd in parCallCmd.CallCmds)
- {
- AddAvailableVars(callCmd, start);
- }
- }
- private HashSet<Variable> PropagateAvailableLinearVarsAcrossBlock(Block b) {
- HashSet<Variable> start = new HashSet<Variable>(availableLinearVars[b]);
- foreach (Cmd cmd in b.Cmds)
- {
- if (cmd is AssignCmd)
- {
- AssignCmd assignCmd = (AssignCmd)cmd;
- for (int i = 0; i < assignCmd.Lhss.Count; i++)
- {
- if (FindDomainName(assignCmd.Lhss[i].DeepAssignedVariable) == null) continue;
- IdentifierExpr ie = assignCmd.Rhss[i] as IdentifierExpr;
- if (!start.Contains(ie.Decl))
- {
- Error(ie, "unavailable source for a linear read");
- }
- else
- {
- start.Remove(ie.Decl);
- }
- }
- foreach (AssignLhs assignLhs in assignCmd.Lhss)
- {
- if (FindDomainName(assignLhs.DeepAssignedVariable) == null) continue;
- start.Add(assignLhs.DeepAssignedVariable);
- }
- }
- else if (cmd is CallCmd)
- {
- foreach (GlobalVariable g in globalVarToDomainName.Keys.Except(start))
- {
- Error(cmd, string.Format("Global variable {0} must be available at a call", g.Name));
- }
- CallCmd callCmd = (CallCmd)cmd;
- for (int i = 0; i < callCmd.Proc.InParams.Count; i++)
- {
- Variable param = callCmd.Proc.InParams[i];
- if (FindDomainName(param) == null) continue;
- IdentifierExpr ie = callCmd.Ins[i] as IdentifierExpr;
- LinearKind paramKind = FindLinearKind(param);
- if (start.Contains(ie.Decl))
- {
- if (callCmd.IsAsync || paramKind == LinearKind.LINEAR_IN)
- {
- start.Remove(ie.Decl);
- }
- }
- else
- {
- if (paramKind == LinearKind.LINEAR_OUT)
- {
- start.Add(ie.Decl);
- }
- else
- {
- Error(ie, "unavailable source for a linear read");
- }
- }
- }
- availableLinearVars[callCmd] = new HashSet<Variable>(start);
- AddAvailableVars(callCmd, start);
- }
- else if (cmd is ParCallCmd)
- {
- foreach (GlobalVariable g in globalVarToDomainName.Keys.Except(start))
- {
- Error(cmd, string.Format("Global variable {0} must be available at a call", g.Name));
- }
- ParCallCmd parCallCmd = (ParCallCmd)cmd;
- foreach (CallCmd callCmd in parCallCmd.CallCmds)
- {
- for (int i = 0; i < callCmd.Proc.InParams.Count; i++)
- {
- Variable param = callCmd.Proc.InParams[i];
- if (FindDomainName(param) == null) continue;
- IdentifierExpr ie = callCmd.Ins[i] as IdentifierExpr;
- LinearKind paramKind = FindLinearKind(param);
- if (start.Contains(ie.Decl))
- {
- if (paramKind == LinearKind.LINEAR_IN)
- {
- start.Remove(ie.Decl);
- }
- }
- else
- {
- if (paramKind == LinearKind.LINEAR_OUT)
- {
- start.Add(ie.Decl);
- }
- else
- {
- Error(ie, "unavailable source for a linear read");
- }
- }
- }
- }
- availableLinearVars[parCallCmd] = new HashSet<Variable>(start);
- AddAvailableVars(parCallCmd, start);
- }
- else if (cmd is HavocCmd)
- {
- HavocCmd havocCmd = (HavocCmd)cmd;
- foreach (IdentifierExpr ie in havocCmd.Vars)
- {
- if (FindDomainName(ie.Decl) == null) continue;
- start.Remove(ie.Decl);
- }
- }
- else if (cmd is YieldCmd)
- {
- foreach (GlobalVariable g in globalVarToDomainName.Keys.Except(start))
- {
- Error(cmd, string.Format("Global variable {0} must be available at a yield", g.Name));
- }
- availableLinearVars[cmd] = new HashSet<Variable>(start);
- }
- }
- return start;
- }
- public string FindDomainName(Variable v)
- {
- if (globalVarToDomainName.ContainsKey(v))
- return globalVarToDomainName[v];
- if (inParamToLinearQualifier.ContainsKey(v))
- return inParamToLinearQualifier[v].domainName;
- if (outParamToDomainName.ContainsKey(v))
- return outParamToDomainName[v];
- string domainName = QKeyValue.FindStringAttribute(v.Attributes, "linear");
- if (domainName != null)
- return domainName;
- domainName = QKeyValue.FindStringAttribute(v.Attributes, "linear_in");
- if (domainName != null)
- return domainName;
- return QKeyValue.FindStringAttribute(v.Attributes, "linear_out");
- }
- public LinearKind FindLinearKind(Variable v)
- {
- if (globalVarToDomainName.ContainsKey(v))
- return LinearKind.LINEAR;
- if (inParamToLinearQualifier.ContainsKey(v))
- return inParamToLinearQualifier[v].kind;
- if (outParamToDomainName.ContainsKey(v))
- return LinearKind.LINEAR;
-
- if (QKeyValue.FindStringAttribute(v.Attributes, "linear") != null)
- {
- return LinearKind.LINEAR;
- }
- else if (QKeyValue.FindStringAttribute(v.Attributes, "linear_in") != null)
- {
- return LinearKind.LINEAR_IN;
- }
- else if (QKeyValue.FindStringAttribute(v.Attributes, "linear_out") != null)
- {
- return LinearKind.LINEAR_OUT;
- }
- else
- {
- Debug.Assert(false);
- return LinearKind.LINEAR;
- }
- }
- public override Variable VisitVariable(Variable node)
- {
- string domainName = FindDomainName(node);
- if (domainName != null)
- {
- if (!domainNameToCollectors.ContainsKey(domainName))
- {
- domainNameToCollectors[domainName] = new Dictionary<Type,Function>();
- }
- LinearKind kind = FindLinearKind(node);
- if (kind != LinearKind.LINEAR)
- {
- if (node is GlobalVariable || node is LocalVariable || (node is Formal && !(node as Formal).InComing))
- {
- Error(node, "Variable must be declared linear (as opposed to linear_in or linear_out)");
- }
- }
- }
- return base.VisitVariable(node);
- }
- public override Cmd VisitAssignCmd(AssignCmd node)
- {
- HashSet<Variable> rhsVars = new HashSet<Variable>();
- for (int i = 0; i < node.Lhss.Count; i++)
- {
- AssignLhs lhs = node.Lhss[i];
- Variable lhsVar = lhs.DeepAssignedVariable;
- string domainName = FindDomainName(lhsVar);
- if (domainName == null) continue;
- SimpleAssignLhs salhs = lhs as SimpleAssignLhs;
- if (salhs == null)
- {
- Error(node, string.Format("Only simple assignment allowed on linear variable {0}", lhsVar.Name));
- continue;
- }
- IdentifierExpr rhs = node.Rhss[i] as IdentifierExpr;
- if (rhs == null)
- {
- Error(node, string.Format("Only variable can be assigned to linear variable {0}", lhsVar.Name));
- continue;
- }
- string rhsDomainName = FindDomainName(rhs.Decl);
- if (rhsDomainName == null)
- {
- Error(node, string.Format("Only linear variable can be assigned to linear variable {0}", lhsVar.Name));
- continue;
- }
- if (domainName != rhsDomainName)
- {
- Error(node, string.Format("Linear variable of domain {0} cannot be assigned to linear variable of domain {1}", rhsDomainName, domainName));
- continue;
- }
- if (rhsVars.Contains(rhs.Decl))
- {
- Error(node, string.Format("Linear variable {0} can occur only once in the right-hand-side of an assignment", rhs.Decl.Name));
- continue;
- }
- rhsVars.Add(rhs.Decl);
- }
- return base.VisitAssignCmd(node);
- }
- public override Cmd VisitCallCmd(CallCmd node)
- {
- HashSet<Variable> inVars = new HashSet<Variable>();
- for (int i = 0; i < node.Proc.InParams.Count; i++)
- {
- Variable formal = node.Proc.InParams[i];
- string domainName = FindDomainName(formal);
- if (domainName == null) continue;
- IdentifierExpr actual = node.Ins[i] as IdentifierExpr;
- if (actual == null)
- {
- Error(node, string.Format("Only variable can be passed to linear parameter {0}", formal.Name));
- continue;
- }
- string actualDomainName = FindDomainName(actual.Decl);
- if (actualDomainName == null)
- {
- Error(node, string.Format("Only a linear argument can be passed to linear parameter {0}", formal.Name));
- continue;
- }
- if (domainName != actualDomainName)
- {
- Error(node, "The domains of formal and actual parameters must be the same");
- continue;
- }
- if (actual.Decl is GlobalVariable)
- {
- Error(node, "Only local linear variable can be an actual input parameter of a procedure call");
- continue;
- }
- if (inVars.Contains(actual.Decl))
- {
- Error(node, string.Format("Linear variable {0} can occur only once as an input parameter", actual.Decl.Name));
- continue;
- }
- inVars.Add(actual.Decl);
- }
- for (int i = 0; i < node.Proc.OutParams.Count; i++)
- {
- IdentifierExpr actual = node.Outs[i];
- string actualDomainName = FindDomainName(actual.Decl);
- if (actualDomainName == null) continue;
- Variable formal = node.Proc.OutParams[i];
- string domainName = FindDomainName(formal);
- if (domainName == null)
- {
- Error(node, "Only a linear variable can be passed to a linear parameter");
- continue;
- }
- if (domainName != actualDomainName)
- {
- Error(node, "The domains of formal and actual parameters must be the same");
- continue;
- }
- if (actual.Decl is GlobalVariable)
- {
- Error(node, "Only local linear variable can be actual output parameter of a procedure call");
- continue;
- }
- }
- return base.VisitCallCmd(node);
- }
- public override Cmd VisitParCallCmd(ParCallCmd node)
- {
- HashSet<Variable> parallelCallInvars = new HashSet<Variable>();
- foreach (CallCmd callCmd in node.CallCmds)
- {
- for (int i = 0; i < callCmd.Proc.InParams.Count; i++)
- {
- Variable formal = callCmd.Proc.InParams[i];
- string domainName = FindDomainName(formal);
- if (domainName == null) continue;
- IdentifierExpr actual = callCmd.Ins[i] as IdentifierExpr;
- if (parallelCallInvars.Contains(actual.Decl))
- {
- Error(node, string.Format("Linear variable {0} can occur only once as an input parameter of a parallel call", actual.Decl.Name));
- }
- else
- {
- parallelCallInvars.Add(actual.Decl);
- }
- }
- }
- return base.VisitParCallCmd(node);
- }
-
- public override Requires VisitRequires(Requires requires)
- {
- return requires;
- }
-
- public override Ensures VisitEnsures(Ensures ensures)
- {
- return ensures;
- }
-
- public IEnumerable<Variable> AvailableLinearVars(Absy absy)
- {
- if (availableLinearVars.ContainsKey(absy))
- {
- return availableLinearVars[absy];
- }
- else
- {
- return new HashSet<Variable>();
- }
- }
-
- private void AddDisjointnessExpr(List<Cmd> newCmds, Absy absy, Dictionary<string, Variable> domainNameToInputVar)
- {
- Dictionary<string, HashSet<Variable>> domainNameToScope = new Dictionary<string, HashSet<Variable>>();
- foreach (var domainName in linearDomains.Keys)
- {
- domainNameToScope[domainName] = new HashSet<Variable>();
- }
- foreach (Variable v in AvailableLinearVars(absy))
- {
- var domainName = FindDomainName(v);
- domainNameToScope[domainName].Add(v);
- }
- foreach (Variable v in program.GlobalVariables)
- {
- var domainName = FindDomainName(v);
- if (domainName == null) continue;
- domainNameToScope[domainName].Add(v);
- }
- foreach (string domainName in linearDomains.Keys)
- {
- newCmds.Add(new AssumeCmd(Token.NoToken, DisjointnessExpr(domainName, domainNameToInputVar[domainName], domainNameToScope[domainName])));
- }
- }
-
- public void Transform()
- {
- foreach (var impl in program.Implementations)
- {
- Dictionary<string, Variable> domainNameToInputVar = new Dictionary<string, Variable>();
- foreach (string domainName in linearDomains.Keys)
- {
- var domain = linearDomains[domainName];
- Formal f = new Formal(
- Token.NoToken,
- new TypedIdent(Token.NoToken,
- "linear_" + domainName + "_in",
- new MapType(Token.NoToken, new List<TypeVariable>(),
- new List<Type> { domain.elementType }, Type.Bool)), true);
- impl.InParams.Add(f);
- domainNameToInputVar[domainName] = f;
- }
-
- foreach (Block b in impl.Blocks)
- {
- List<Cmd> newCmds = new List<Cmd>();
- for (int i = 0; i < b.Cmds.Count; i++)
- {
- Cmd cmd = b.Cmds[i];
- newCmds.Add(cmd);
- if (cmd is CallCmd)
- {
- CallCmd callCmd = cmd as CallCmd;
- if (callCmd.IsAsync)
- {
- foreach (var domainName in linearDomains.Keys)
- {
- var domain = linearDomains[domainName];
- var expr = new NAryExpr(Token.NoToken, new FunctionCall(domain.mapConstBool), new List<Expr> { Expr.False });
- expr.Resolve(new ResolutionContext(null));
- expr.Typecheck(new TypecheckingContext(null));
- callCmd.Ins.Add(expr);
- }
- }
- else
- {
- Dictionary<string, Expr> domainNameToExpr = new Dictionary<string, Expr>();
- foreach (var domainName in linearDomains.Keys)
- {
- domainNameToExpr[domainName] = Expr.Ident(domainNameToInputVar[domainName]);
- }
- foreach (Variable v in AvailableLinearVars(callCmd))
- {
- var domainName = FindDomainName(v);
- var domain = linearDomains[domainName];
- if (!domain.collectors.ContainsKey(v.TypedIdent.Type)) continue;
- Expr ie = new NAryExpr(Token.NoToken, new FunctionCall(domain.collectors[v.TypedIdent.Type]), new List<Expr> { Expr.Ident(v) });
- var expr = new NAryExpr(Token.NoToken, new FunctionCall(domain.mapOrBool), new List<Expr> { ie, domainNameToExpr[domainName] });
- expr.Resolve(new ResolutionContext(null));
- expr.Typecheck(new TypecheckingContext(null));
- domainNameToExpr[domainName] = expr;
- }
- foreach (var domainName in linearDomains.Keys)
- {
- callCmd.Ins.Add(domainNameToExpr[domainName]);
- }
- }
- }
- else if (cmd is ParCallCmd)
- {
- ParCallCmd parCallCmd = (ParCallCmd)cmd;
- foreach (CallCmd callCmd in parCallCmd.CallCmds)
- {
- foreach (var domainName in linearDomains.Keys)
- {
- var domain = linearDomains[domainName];
- var expr = new NAryExpr(Token.NoToken, new FunctionCall(domain.mapConstBool), new List<Expr> { Expr.False });
- expr.Resolve(new ResolutionContext(null));
- expr.Typecheck(new TypecheckingContext(null));
- callCmd.Ins.Add(expr);
- }
- }
- }
- else if (cmd is YieldCmd)
- {
- AddDisjointnessExpr(newCmds, cmd, domainNameToInputVar);
- }
- }
- b.Cmds = newCmds;
- }
-
- {
- // Loops
- impl.PruneUnreachableBlocks();
- impl.ComputePredecessorsForBlocks();
- GraphUtil.Graph<Block> g = Program.GraphFromImpl(impl);
- g.ComputeLoops();
- if (g.Reducible)
- {
- foreach (Block header in g.Headers)
- {
- List<Cmd> newCmds = new List<Cmd>();
- AddDisjointnessExpr(newCmds, header, domainNameToInputVar);
- newCmds.AddRange(header.Cmds);
- header.Cmds = newCmds;
- }
- }
- }
- }
-
- foreach (var proc in program.Procedures)
- {
- Dictionary<string, HashSet<Variable>> domainNameToInputScope = new Dictionary<string, HashSet<Variable>>();
- Dictionary<string, HashSet<Variable>> domainNameToOutputScope = new Dictionary<string, HashSet<Variable>>();
- foreach (var domainName in linearDomains.Keys)
- {
- domainNameToInputScope[domainName] = new HashSet<Variable>();
- domainNameToOutputScope[domainName] = new HashSet<Variable>();
-
- }
- foreach (Variable v in globalVarToDomainName.Keys)
- {
- var domainName = globalVarToDomainName[v];
- domainNameToInputScope[domainName].Add(v);
- domainNameToOutputScope[domainName].Add(v);
- }
- foreach (Variable v in proc.InParams)
- {
- var domainName = FindDomainName(v);
- if (domainName == null) continue;
- if (!this.linearDomains.ContainsKey(domainName)) continue;
- domainNameToInputScope[domainName].Add(v);
- }
- foreach (Variable v in proc.OutParams)
- {
- var domainName = FindDomainName(v);
- if (domainName == null) continue;
- if (!this.linearDomains.ContainsKey(domainName)) continue;
- domainNameToOutputScope[domainName].Add(v);
- }
- foreach (var domainName in linearDomains.Keys)
- {
- proc.Requires.Add(new Requires(true, DisjointnessExpr(domainName, domainNameToInputScope[domainName])));
- var domain = linearDomains[domainName];
- Formal f = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "linear_" + domainName + "_in", new MapType(Token.NoToken, new List<TypeVariable>(), new List<Type> { domain.elementType }, Type.Bool)), true);
- proc.InParams.Add(f);
- proc.Ensures.Add(new Ensures(true, DisjointnessExpr(domainName, f, domainNameToOutputScope[domainName])));
- }
- }
-
- foreach (LinearDomain domain in linearDomains.Values)
- {
- program.AddTopLevelDeclaration(domain.mapConstBool);
- program.AddTopLevelDeclaration(domain.mapConstInt);
- program.AddTopLevelDeclaration(domain.mapEqInt);
- program.AddTopLevelDeclaration(domain.mapImpBool);
- program.AddTopLevelDeclaration(domain.mapOrBool);
- foreach (Axiom axiom in domain.axioms)
- {
- program.AddTopLevelDeclaration(axiom);
- }
- }
-
- //int oldPrintUnstructured = CommandLineOptions.Clo.PrintUnstructured;
- //CommandLineOptions.Clo.PrintUnstructured = 1;
- //PrintBplFile("lsd.bpl", program, false, false);
- //CommandLineOptions.Clo.PrintUnstructured = oldPrintUnstructured;
- }
-
- private Expr SubsetExpr(LinearDomain domain, Expr ie, Variable partition, int partitionCount)
- {
- Expr e = new NAryExpr(Token.NoToken, new FunctionCall(domain.mapConstInt), new List<Expr> { new LiteralExpr(Token.NoToken, Microsoft.Basetypes.BigNum.FromInt(partitionCount)) });
- e = new NAryExpr(Token.NoToken, new FunctionCall(domain.mapEqInt), new List<Expr> { Expr.Ident(partition), e });
- e = new NAryExpr(Token.NoToken, new FunctionCall(domain.mapImpBool), new List<Expr> { ie, e });
- e = Expr.Eq(e, new NAryExpr(Token.NoToken, new FunctionCall(domain.mapConstBool), new List<Expr> { Expr.True }));
- return e;
- }
-
- private Expr SubsetExprs(LinearDomain domain, HashSet<Variable> scope, Variable partition, int count, Expr expr)
- {
- foreach (Variable v in scope)
- {
- if (!domain.collectors.ContainsKey(v.TypedIdent.Type)) continue;
- Expr ie = new NAryExpr(Token.NoToken, new FunctionCall(domain.collectors[v.TypedIdent.Type]), new List<Expr> { Expr.Ident(v) });
- expr = Expr.And(SubsetExpr(domain, ie, partition, count), expr);
- count++;
- }
- expr = new ExistsExpr(Token.NoToken, new List<Variable> { partition }, expr);
- expr.Resolve(new ResolutionContext(null));
- expr.Typecheck(new TypecheckingContext(null));
- return expr;
- }
-
- public Expr DisjointnessExpr(string domainName, Variable inputVar, HashSet<Variable> scope)
- {
- LinearDomain domain = linearDomains[domainName];
- BoundVariable partition = new BoundVariable(Token.NoToken, new TypedIdent(Token.NoToken, string.Format("partition_{0}", domainName), new MapType(Token.NoToken, new List<TypeVariable>(), new List<Type> { domain.elementType }, Microsoft.Boogie.Type.Int)));
- return SubsetExprs(domain, scope, partition, 1, SubsetExpr(domain, Expr.Ident(inputVar), partition, 0));
- }
-
- public Expr DisjointnessExpr(string domainName, HashSet<Variable> scope)
- {
- LinearDomain domain = linearDomains[domainName];
- BoundVariable partition = new BoundVariable(Token.NoToken, new TypedIdent(Token.NoToken, string.Format("partition_{0}", domainName), new MapType(Token.NoToken, new List<TypeVariable>(), new List<Type> { domain.elementType }, Microsoft.Boogie.Type.Int)));
- return SubsetExprs(domain, scope, partition, 0, Expr.True);
- }
- }
-
- public class LinearQualifier
- {
- public string domainName;
- public LinearKind kind;
- public LinearQualifier(string domainName, LinearKind kind)
- {
- this.domainName = domainName;
- this.kind = kind;
- }
- }
-
- public class LinearDomain
- {
- public Function mapEqInt;
- public Function mapConstInt;
- public Function mapOrBool;
- public Function mapImpBool;
- public Function mapConstBool;
- public List<Axiom> axioms;
- public Type elementType;
- public Dictionary<Type, Function> collectors;
-
- public LinearDomain(Program program, string domainName, Dictionary<Type, Function> collectors)
- {
- this.axioms = new List<Axiom>();
- this.collectors = collectors;
- MapType setType = (MapType)collectors.First().Value.OutParams[0].TypedIdent.Type;
- this.elementType = setType.Arguments[0];
- MapType mapTypeBool = new MapType(Token.NoToken, new List<TypeVariable>(), new List<Type> { this.elementType }, Type.Bool);
- MapType mapTypeInt = new MapType(Token.NoToken, new List<TypeVariable>(), new List<Type> { this.elementType }, Type.Int);
- this.mapOrBool = new Function(Token.NoToken, "linear_" + domainName + "_MapOr",
- new List<Variable> { new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "a", mapTypeBool), true),
- new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "b", mapTypeBool), true) },
- new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "c", mapTypeBool), false));
- if (CommandLineOptions.Clo.UseArrayTheory)
- {
- this.mapOrBool.AddAttribute("builtin", "MapOr");
- }
- else
- {
- BoundVariable a = new BoundVariable(Token.NoToken, new TypedIdent(Token.NoToken, "a", mapTypeBool));
- IdentifierExpr aie = Expr.Ident(a);
- BoundVariable b = new BoundVariable(Token.NoToken, new TypedIdent(Token.NoToken, "b", mapTypeBool));
- IdentifierExpr bie = Expr.Ident(b);
- BoundVariable x = new BoundVariable(Token.NoToken, new TypedIdent(Token.NoToken, "x", elementType));
- IdentifierExpr xie = Expr.Ident(x);
- var mapApplTerm = new NAryExpr(Token.NoToken, new FunctionCall(mapOrBool), new List<Expr> { aie, bie } );
- var lhsTerm = new NAryExpr(Token.NoToken, new MapSelect(Token.NoToken, 1), new List<Expr> { mapApplTerm, xie } );
- var rhsTerm = Expr.Or(new NAryExpr(Token.NoToken, new MapSelect(Token.NoToken, 1), new List<Expr> { aie, xie } ),
- new NAryExpr(Token.NoToken, new MapSelect(Token.NoToken, 1), new List<Expr> { bie, xie} ));
- var axiomExpr = new ForallExpr(Token.NoToken, new List<TypeVariable>(), new List<Variable> { a, b }, null,
- new Trigger(Token.NoToken, true, new List<Expr> { mapApplTerm }),
- new ForallExpr(Token.NoToken, new List<Variable> { x }, Expr.Binary(BinaryOperator.Opcode.Eq, lhsTerm, rhsTerm)));
- axiomExpr.Typecheck(new TypecheckingContext(null));
- axioms.Add(new Axiom(Token.NoToken, axiomExpr));
- }
-
- this.mapImpBool = new Function(Token.NoToken, "linear_" + domainName + "_MapImp",
- new List<Variable> { new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "a", mapTypeBool), true),
- new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "b", mapTypeBool), true) },
- new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "c", mapTypeBool), false));
- if (CommandLineOptions.Clo.UseArrayTheory)
- {
- this.mapImpBool.AddAttribute("builtin", "MapImp");
- }
- else
- {
- BoundVariable a = new BoundVariable(Token.NoToken, new TypedIdent(Token.NoToken, "a", mapTypeBool));
- IdentifierExpr aie = Expr.Ident(a);
- BoundVariable b = new BoundVariable(Token.NoToken, new TypedIdent(Token.NoToken, "b", mapTypeBool));
- IdentifierExpr bie = Expr.Ident(b);
- BoundVariable x = new BoundVariable(Token.NoToken, new TypedIdent(Token.NoToken, "x", elementType));
- IdentifierExpr xie = Expr.Ident(x);
- var mapApplTerm = new NAryExpr(Token.NoToken, new FunctionCall(mapImpBool), new List<Expr> { aie, bie });
- var lhsTerm = new NAryExpr(Token.NoToken, new MapSelect(Token.NoToken, 1), new List<Expr> { mapApplTerm, xie });
- var rhsTerm = Expr.Imp(new NAryExpr(Token.NoToken, new MapSelect(Token.NoToken, 1), new List<Expr> { aie, xie }),
- new NAryExpr(Token.NoToken, new MapSelect(Token.NoToken, 1), new List<Expr> { bie, xie }));
- var axiomExpr = new ForallExpr(Token.NoToken, new List<TypeVariable>(), new List<Variable> { a, b }, null,
- new Trigger(Token.NoToken, true, new List<Expr> { mapApplTerm }),
- new ForallExpr(Token.NoToken, new List<Variable> { x }, Expr.Binary(BinaryOperator.Opcode.Eq, lhsTerm, rhsTerm)));
- axiomExpr.Typecheck(new TypecheckingContext(null));
- axioms.Add(new Axiom(Token.NoToken, axiomExpr));
- }
-
- this.mapConstBool = new Function(Token.NoToken, "linear_" + domainName + "_MapConstBool",
- new List<Variable> { new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "b", Type.Bool), true) },
- new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "c", mapTypeBool), false));
- if (CommandLineOptions.Clo.UseArrayTheory)
- {
- this.mapConstBool.AddAttribute("builtin", "MapConst");
- }
- else
- {
- BoundVariable x = new BoundVariable(Token.NoToken, new TypedIdent(Token.NoToken, "x", elementType));
- IdentifierExpr xie = Expr.Ident(x);
- var trueTerm = new NAryExpr(Token.NoToken, new MapSelect(Token.NoToken, 1),
- new List<Expr> { new NAryExpr(Token.NoToken, new FunctionCall(mapConstBool), new List<Expr> { Expr.True }), xie });
- var trueAxiomExpr = new ForallExpr(Token.NoToken, new List<Variable> { x }, trueTerm);
- trueAxiomExpr.Typecheck(new TypecheckingContext(null));
- axioms.Add(new Axiom(Token.NoToken, trueAxiomExpr));
- var falseTerm = new NAryExpr(Token.NoToken, new MapSelect(Token.NoToken, 1),
- new List<Expr> { new NAryExpr(Token.NoToken, new FunctionCall(mapConstBool), new List<Expr> { Expr.False }), xie });
- var falseAxiomExpr = new ForallExpr(Token.NoToken, new List<Variable> { x }, Expr.Unary(Token.NoToken, UnaryOperator.Opcode.Not, falseTerm));
- falseAxiomExpr.Typecheck(new TypecheckingContext(null));
- axioms.Add(new Axiom(Token.NoToken, falseAxiomExpr));
- }
-
- this.mapEqInt = new Function(Token.NoToken, "linear_" + domainName + "_MapEq",
- new List<Variable> { new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "a", mapTypeInt), true),
- new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "b", mapTypeInt), true) },
- new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "c", mapTypeBool), false));
- if (CommandLineOptions.Clo.UseArrayTheory)
- {
- this.mapEqInt.AddAttribute("builtin", "MapEq");
- }
- else
- {
- BoundVariable a = new BoundVariable(Token.NoToken, new TypedIdent(Token.NoToken, "a", mapTypeInt));
- IdentifierExpr aie = Expr.Ident(a);
- BoundVariable b = new BoundVariable(Token.NoToken, new TypedIdent(Token.NoToken, "b", mapTypeInt));
- IdentifierExpr bie = Expr.Ident(b);
- BoundVariable x = new BoundVariable(Token.NoToken, new TypedIdent(Token.NoToken, "x", elementType));
- IdentifierExpr xie = Expr.Ident(x);
- var mapApplTerm = new NAryExpr(Token.NoToken, new FunctionCall(mapEqInt), new List<Expr> { aie, bie });
- var lhsTerm = new NAryExpr(Token.NoToken, new MapSelect(Token.NoToken, 1), new List<Expr> { mapApplTerm, xie });
- var rhsTerm = Expr.Eq(new NAryExpr(Token.NoToken, new MapSelect(Token.NoToken, 1), new List<Expr> { aie, xie }),
- new NAryExpr(Token.NoToken, new MapSelect(Token.NoToken, 1), new List<Expr> { bie, xie }));
- var axiomExpr = new ForallExpr(Token.NoToken, new List<TypeVariable>(), new List<Variable> { a, b }, null,
- new Trigger(Token.NoToken, true, new List<Expr> { mapApplTerm }),
- new ForallExpr(Token.NoToken, new List<Variable> { x }, Expr.Binary(BinaryOperator.Opcode.Eq, lhsTerm, rhsTerm)));
- axiomExpr.Typecheck(new TypecheckingContext(null));
- axioms.Add(new Axiom(Token.NoToken, axiomExpr));
- }
-
- this.mapConstInt = new Function(Token.NoToken, "linear_" + domainName + "_MapConstInt",
- new List<Variable> { new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "b", Type.Int), true) },
- new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "c", mapTypeInt), false));
- if (CommandLineOptions.Clo.UseArrayTheory)
- {
- this.mapConstInt.AddAttribute("builtin", "MapConst");
- }
- else
- {
- BoundVariable a = new BoundVariable(Token.NoToken, new TypedIdent(Token.NoToken, "a", Type.Int));
- IdentifierExpr aie = Expr.Ident(a);
- BoundVariable x = new BoundVariable(Token.NoToken, new TypedIdent(Token.NoToken, "x", elementType));
- IdentifierExpr xie = Expr.Ident(x);
- var lhsTerm = new NAryExpr(Token.NoToken, new MapSelect(Token.NoToken, 1), new List<Expr> { new NAryExpr(Token.NoToken, new FunctionCall(mapConstInt), new List<Expr> { aie }), xie });
- var axiomExpr = new ForallExpr(Token.NoToken, new List<Variable> { a, x }, Expr.Binary(BinaryOperator.Opcode.Eq, lhsTerm, aie));
- axiomExpr.Typecheck(new TypecheckingContext(null));
- axioms.Add(new Axiom(Token.NoToken, axiomExpr));
- }
-
- foreach (var axiom in axioms)
- {
- axiom.Expr.Resolve(new ResolutionContext(null));
- axiom.Expr.Typecheck(new TypecheckingContext(null));
- }
- }
- }
-}
+using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.Boogie; +using System.Diagnostics; + +namespace Microsoft.Boogie +{ + public class LinearEraser : ReadOnlyVisitor + { + private QKeyValue RemoveLinearAttribute(QKeyValue iter) + { + if (iter == null) return null; + iter.Next = RemoveLinearAttribute(iter.Next); + return (iter.Key == "linear" || iter.Key == "linear_in" || iter.Key == "linear_out") ? iter.Next : iter; + } + + public override Variable VisitVariable(Variable node) + { + node.Attributes = RemoveLinearAttribute(node.Attributes); + return base.VisitVariable(node); + } + + public override Function VisitFunction(Function node) + { + node.Attributes = RemoveLinearAttribute(node.Attributes); + return base.VisitFunction(node); + } + } + + public enum LinearKind { + LINEAR, + LINEAR_IN, + LINEAR_OUT + } + + public class LinearTypeChecker : ReadOnlyVisitor + { + public Program program; + public int errorCount; + public CheckingContext checkingContext; + public Dictionary<string, Dictionary<Type, Function>> domainNameToCollectors; + private Dictionary<Absy, HashSet<Variable>> availableLinearVars; + public Dictionary<Variable, LinearQualifier> inParamToLinearQualifier; + public Dictionary<Variable, string> outParamToDomainName; + public Dictionary<Variable, string> varToDomainName; + public Dictionary<Variable, string> globalVarToDomainName; + public Dictionary<string, LinearDomain> linearDomains; + + public LinearTypeChecker(Program program) + { + this.program = program; + this.errorCount = 0; + this.checkingContext = new CheckingContext(null); + this.domainNameToCollectors = new Dictionary<string, Dictionary<Type, Function>>(); + this.availableLinearVars = new Dictionary<Absy, HashSet<Variable>>(); + this.inParamToLinearQualifier = new Dictionary<Variable, LinearQualifier>(); + this.outParamToDomainName = new Dictionary<Variable, string>(); + this.varToDomainName = new Dictionary<Variable, string>(); + this.globalVarToDomainName = new Dictionary<Variable, string>(); + this.linearDomains = new Dictionary<string, LinearDomain>(); + } + public void TypeCheck() + { + this.VisitProgram(program); + foreach (string domainName in domainNameToCollectors.Keys) + { + var collectors = domainNameToCollectors[domainName]; + if (collectors.Count == 0) continue; + this.linearDomains[domainName] = new LinearDomain(program, domainName, collectors); + } + Dictionary<Absy, HashSet<Variable>> newAvailableLinearVars = new Dictionary<Absy, HashSet<Variable>>(); + foreach (Absy absy in this.availableLinearVars.Keys) + { + HashSet<Variable> vars = new HashSet<Variable>(); + foreach (Variable var in this.availableLinearVars[absy]) + { + if (var is GlobalVariable) continue; + string domainName = FindDomainName(var); + if (this.linearDomains.ContainsKey(domainName)) + { + vars.Add(var); + } + } + newAvailableLinearVars[absy] = vars; + } + this.availableLinearVars = newAvailableLinearVars; + var temp = new Dictionary<Variable, string>(); + foreach (Variable v in outParamToDomainName.Keys) + { + if (linearDomains.ContainsKey(outParamToDomainName[v])) + temp[v] = outParamToDomainName[v]; + } + this.outParamToDomainName = temp; + temp = new Dictionary<Variable, string>(); + foreach (Variable v in varToDomainName.Keys) + { + if (linearDomains.ContainsKey(varToDomainName[v])) + temp[v] = varToDomainName[v]; + } + this.varToDomainName = temp; + temp = new Dictionary<Variable, string>(); + foreach (Variable v in globalVarToDomainName.Keys) + { + if (linearDomains.ContainsKey(globalVarToDomainName[v])) + temp[v] = globalVarToDomainName[v]; + } + this.globalVarToDomainName = temp; + } + private void Error(Absy node, string message) + { + checkingContext.Error(node, message); + errorCount++; + } + public override Program VisitProgram(Program node) + { + foreach (GlobalVariable g in program.GlobalVariables) + { + string domainName = FindDomainName(g); + if (domainName != null) + { + globalVarToDomainName[g] = domainName; + } + } + return base.VisitProgram(node); + } + public override Function VisitFunction(Function node) + { + string domainName = QKeyValue.FindStringAttribute(node.Attributes, "linear"); + if (domainName != null) + { + if (!domainNameToCollectors.ContainsKey(domainName)) + { + domainNameToCollectors[domainName] = new Dictionary<Type, Function>(); + } + if (node.InParams.Count == 1 && node.OutParams.Count == 1) + { + Type inType = node.InParams[0].TypedIdent.Type; + MapType outType = node.OutParams[0].TypedIdent.Type as MapType; + if (domainNameToCollectors[domainName].ContainsKey(inType)) + { + Error(node, string.Format("A collector for domain for input type has already been defined")); + } + else if (outType == null || outType.Arguments.Count != 1 || !outType.Result.Equals(Type.Bool)) + { + Error(node, "Output of a linear domain collector should be of set type"); + } + else + { + domainNameToCollectors[domainName][inType] = node; + } + } + else + { + Error(node, "Linear domain collector should have one input and one output parameter"); + } + } + return base.VisitFunction(node); + } + public override Implementation VisitImplementation(Implementation node) + { + node.PruneUnreachableBlocks(); + node.ComputePredecessorsForBlocks(); + GraphUtil.Graph<Block> graph = Program.GraphFromImpl(node); + graph.ComputeLoops(); + + HashSet<Variable> start = new HashSet<Variable>(globalVarToDomainName.Keys); + for (int i = 0; i < node.InParams.Count; i++) + { + Variable v = node.Proc.InParams[i]; + string domainName = FindDomainName(v); + if (domainName != null) + { + var kind = FindLinearKind(v); + inParamToLinearQualifier[node.InParams[i]] = new LinearQualifier(domainName, kind); + if (kind == LinearKind.LINEAR || kind == LinearKind.LINEAR_IN) + { + start.Add(node.InParams[i]); + } + } + } + for (int i = 0; i < node.OutParams.Count; i++) + { + string domainName = FindDomainName(node.Proc.OutParams[i]); + if (domainName != null) + { + outParamToDomainName[node.OutParams[i]] = domainName; + } + } + + var oldErrorCount = this.errorCount; + var impl = base.VisitImplementation(node); + if (oldErrorCount < this.errorCount) + return impl; + + Stack<Block> dfsStack = new Stack<Block>(); + HashSet<Block> dfsStackAsSet = new HashSet<Block>(); + availableLinearVars[node.Blocks[0]] = start; + dfsStack.Push(node.Blocks[0]); + dfsStackAsSet.Add(node.Blocks[0]); + while (dfsStack.Count > 0) + { + Block b = dfsStack.Pop(); + dfsStackAsSet.Remove(b); + HashSet<Variable> end = PropagateAvailableLinearVarsAcrossBlock(b); + if (b.TransferCmd is ReturnCmd) + { + foreach (GlobalVariable g in globalVarToDomainName.Keys.Except(end)) + { + Error(b.TransferCmd, string.Format("Global variable {0} must be available at a return", g.Name)); + } + foreach (Variable v in node.InParams) + { + if (FindDomainName(v) == null || FindLinearKind(v) == LinearKind.LINEAR_IN || end.Contains(v)) continue; + Error(b.TransferCmd, string.Format("Input variable {0} must be available at a return", v.Name)); + } + foreach (Variable v in node.OutParams) + { + if (FindDomainName(v) == null || end.Contains(v)) continue; + Error(b.TransferCmd, string.Format("Output variable {0} must be available at a return", v.Name)); + } + continue; + } + GotoCmd gotoCmd = b.TransferCmd as GotoCmd; + foreach (Block target in gotoCmd.labelTargets) + { + if (!availableLinearVars.ContainsKey(target)) + { + availableLinearVars[target] = new HashSet<Variable>(end); + dfsStack.Push(target); + dfsStackAsSet.Add(target); + } + else + { + var savedAvailableVars = new HashSet<Variable>(availableLinearVars[target]); + availableLinearVars[target].IntersectWith(end); + if (savedAvailableVars.IsProperSupersetOf(availableLinearVars[target]) && !dfsStackAsSet.Contains(target)) + { + dfsStack.Push(target); + dfsStackAsSet.Add(target); + } + } + } + } + + if (graph.Reducible) + { + foreach (Block header in graph.Headers) + { + foreach (GlobalVariable g in globalVarToDomainName.Keys.Except(availableLinearVars[header])) + { + Error(header, string.Format("Global variable {0} must be available at a loop head", g.Name)); + } + } + } + return impl; + } + public void AddAvailableVars(CallCmd callCmd, HashSet<Variable> start) + { + foreach (IdentifierExpr ie in callCmd.Outs) + { + if (FindDomainName(ie.Decl) == null) continue; + start.Add(ie.Decl); + } + for (int i = 0; i < callCmd.Proc.InParams.Count; i++) + { + IdentifierExpr ie = callCmd.Ins[i] as IdentifierExpr; + if (ie == null) continue; + Variable v = callCmd.Proc.InParams[i]; + if (FindDomainName(v) == null) continue; + if (FindLinearKind(v) == LinearKind.LINEAR_OUT) + { + start.Add(ie.Decl); + } + } + } + public void AddAvailableVars(ParCallCmd parCallCmd, HashSet<Variable> start) + { + foreach (CallCmd callCmd in parCallCmd.CallCmds) + { + AddAvailableVars(callCmd, start); + } + } + private HashSet<Variable> PropagateAvailableLinearVarsAcrossBlock(Block b) { + HashSet<Variable> start = new HashSet<Variable>(availableLinearVars[b]); + foreach (Cmd cmd in b.Cmds) + { + if (cmd is AssignCmd) + { + AssignCmd assignCmd = (AssignCmd)cmd; + for (int i = 0; i < assignCmd.Lhss.Count; i++) + { + if (FindDomainName(assignCmd.Lhss[i].DeepAssignedVariable) == null) continue; + IdentifierExpr ie = assignCmd.Rhss[i] as IdentifierExpr; + if (!start.Contains(ie.Decl)) + { + Error(ie, "unavailable source for a linear read"); + } + else + { + start.Remove(ie.Decl); + } + } + foreach (AssignLhs assignLhs in assignCmd.Lhss) + { + if (FindDomainName(assignLhs.DeepAssignedVariable) == null) continue; + start.Add(assignLhs.DeepAssignedVariable); + } + } + else if (cmd is CallCmd) + { + foreach (GlobalVariable g in globalVarToDomainName.Keys.Except(start)) + { + Error(cmd, string.Format("Global variable {0} must be available at a call", g.Name)); + } + CallCmd callCmd = (CallCmd)cmd; + for (int i = 0; i < callCmd.Proc.InParams.Count; i++) + { + Variable param = callCmd.Proc.InParams[i]; + if (FindDomainName(param) == null) continue; + IdentifierExpr ie = callCmd.Ins[i] as IdentifierExpr; + LinearKind paramKind = FindLinearKind(param); + if (start.Contains(ie.Decl)) + { + if (callCmd.IsAsync || paramKind == LinearKind.LINEAR_IN) + { + start.Remove(ie.Decl); + } + } + else + { + if (paramKind == LinearKind.LINEAR_OUT) + { + start.Add(ie.Decl); + } + else + { + Error(ie, "unavailable source for a linear read"); + } + } + } + availableLinearVars[callCmd] = new HashSet<Variable>(start); + AddAvailableVars(callCmd, start); + } + else if (cmd is ParCallCmd) + { + foreach (GlobalVariable g in globalVarToDomainName.Keys.Except(start)) + { + Error(cmd, string.Format("Global variable {0} must be available at a call", g.Name)); + } + ParCallCmd parCallCmd = (ParCallCmd)cmd; + foreach (CallCmd callCmd in parCallCmd.CallCmds) + { + for (int i = 0; i < callCmd.Proc.InParams.Count; i++) + { + Variable param = callCmd.Proc.InParams[i]; + if (FindDomainName(param) == null) continue; + IdentifierExpr ie = callCmd.Ins[i] as IdentifierExpr; + LinearKind paramKind = FindLinearKind(param); + if (start.Contains(ie.Decl)) + { + if (paramKind == LinearKind.LINEAR_IN) + { + start.Remove(ie.Decl); + } + } + else + { + if (paramKind == LinearKind.LINEAR_OUT) + { + start.Add(ie.Decl); + } + else + { + Error(ie, "unavailable source for a linear read"); + } + } + } + } + availableLinearVars[parCallCmd] = new HashSet<Variable>(start); + AddAvailableVars(parCallCmd, start); + } + else if (cmd is HavocCmd) + { + HavocCmd havocCmd = (HavocCmd)cmd; + foreach (IdentifierExpr ie in havocCmd.Vars) + { + if (FindDomainName(ie.Decl) == null) continue; + start.Remove(ie.Decl); + } + } + else if (cmd is YieldCmd) + { + foreach (GlobalVariable g in globalVarToDomainName.Keys.Except(start)) + { + Error(cmd, string.Format("Global variable {0} must be available at a yield", g.Name)); + } + availableLinearVars[cmd] = new HashSet<Variable>(start); + } + } + return start; + } + public string FindDomainName(Variable v) + { + if (globalVarToDomainName.ContainsKey(v)) + return globalVarToDomainName[v]; + if (inParamToLinearQualifier.ContainsKey(v)) + return inParamToLinearQualifier[v].domainName; + if (outParamToDomainName.ContainsKey(v)) + return outParamToDomainName[v]; + string domainName = QKeyValue.FindStringAttribute(v.Attributes, "linear"); + if (domainName != null) + return domainName; + domainName = QKeyValue.FindStringAttribute(v.Attributes, "linear_in"); + if (domainName != null) + return domainName; + return QKeyValue.FindStringAttribute(v.Attributes, "linear_out"); + } + public LinearKind FindLinearKind(Variable v) + { + if (globalVarToDomainName.ContainsKey(v)) + return LinearKind.LINEAR; + if (inParamToLinearQualifier.ContainsKey(v)) + return inParamToLinearQualifier[v].kind; + if (outParamToDomainName.ContainsKey(v)) + return LinearKind.LINEAR; + + if (QKeyValue.FindStringAttribute(v.Attributes, "linear") != null) + { + return LinearKind.LINEAR; + } + else if (QKeyValue.FindStringAttribute(v.Attributes, "linear_in") != null) + { + return LinearKind.LINEAR_IN; + } + else if (QKeyValue.FindStringAttribute(v.Attributes, "linear_out") != null) + { + return LinearKind.LINEAR_OUT; + } + else + { + Debug.Assert(false); + return LinearKind.LINEAR; + } + } + public override Variable VisitVariable(Variable node) + { + string domainName = FindDomainName(node); + if (domainName != null) + { + if (!domainNameToCollectors.ContainsKey(domainName)) + { + domainNameToCollectors[domainName] = new Dictionary<Type,Function>(); + } + LinearKind kind = FindLinearKind(node); + if (kind != LinearKind.LINEAR) + { + if (node is GlobalVariable || node is LocalVariable || (node is Formal && !(node as Formal).InComing)) + { + Error(node, "Variable must be declared linear (as opposed to linear_in or linear_out)"); + } + } + } + return base.VisitVariable(node); + } + public override Cmd VisitAssignCmd(AssignCmd node) + { + HashSet<Variable> rhsVars = new HashSet<Variable>(); + for (int i = 0; i < node.Lhss.Count; i++) + { + AssignLhs lhs = node.Lhss[i]; + Variable lhsVar = lhs.DeepAssignedVariable; + string domainName = FindDomainName(lhsVar); + if (domainName == null) continue; + SimpleAssignLhs salhs = lhs as SimpleAssignLhs; + if (salhs == null) + { + Error(node, string.Format("Only simple assignment allowed on linear variable {0}", lhsVar.Name)); + continue; + } + IdentifierExpr rhs = node.Rhss[i] as IdentifierExpr; + if (rhs == null) + { + Error(node, string.Format("Only variable can be assigned to linear variable {0}", lhsVar.Name)); + continue; + } + string rhsDomainName = FindDomainName(rhs.Decl); + if (rhsDomainName == null) + { + Error(node, string.Format("Only linear variable can be assigned to linear variable {0}", lhsVar.Name)); + continue; + } + if (domainName != rhsDomainName) + { + Error(node, string.Format("Linear variable of domain {0} cannot be assigned to linear variable of domain {1}", rhsDomainName, domainName)); + continue; + } + if (rhsVars.Contains(rhs.Decl)) + { + Error(node, string.Format("Linear variable {0} can occur only once in the right-hand-side of an assignment", rhs.Decl.Name)); + continue; + } + rhsVars.Add(rhs.Decl); + } + return base.VisitAssignCmd(node); + } + public override Cmd VisitCallCmd(CallCmd node) + { + HashSet<Variable> inVars = new HashSet<Variable>(); + for (int i = 0; i < node.Proc.InParams.Count; i++) + { + Variable formal = node.Proc.InParams[i]; + string domainName = FindDomainName(formal); + if (domainName == null) continue; + IdentifierExpr actual = node.Ins[i] as IdentifierExpr; + if (actual == null) + { + Error(node, string.Format("Only variable can be passed to linear parameter {0}", formal.Name)); + continue; + } + string actualDomainName = FindDomainName(actual.Decl); + if (actualDomainName == null) + { + Error(node, string.Format("Only a linear argument can be passed to linear parameter {0}", formal.Name)); + continue; + } + if (domainName != actualDomainName) + { + Error(node, "The domains of formal and actual parameters must be the same"); + continue; + } + if (actual.Decl is GlobalVariable) + { + Error(node, "Only local linear variable can be an actual input parameter of a procedure call"); + continue; + } + if (inVars.Contains(actual.Decl)) + { + Error(node, string.Format("Linear variable {0} can occur only once as an input parameter", actual.Decl.Name)); + continue; + } + inVars.Add(actual.Decl); + } + for (int i = 0; i < node.Proc.OutParams.Count; i++) + { + IdentifierExpr actual = node.Outs[i]; + string actualDomainName = FindDomainName(actual.Decl); + if (actualDomainName == null) continue; + Variable formal = node.Proc.OutParams[i]; + string domainName = FindDomainName(formal); + if (domainName == null) + { + Error(node, "Only a linear variable can be passed to a linear parameter"); + continue; + } + if (domainName != actualDomainName) + { + Error(node, "The domains of formal and actual parameters must be the same"); + continue; + } + if (actual.Decl is GlobalVariable) + { + Error(node, "Only local linear variable can be actual output parameter of a procedure call"); + continue; + } + } + return base.VisitCallCmd(node); + } + public override Cmd VisitParCallCmd(ParCallCmd node) + { + HashSet<Variable> parallelCallInvars = new HashSet<Variable>(); + foreach (CallCmd callCmd in node.CallCmds) + { + for (int i = 0; i < callCmd.Proc.InParams.Count; i++) + { + Variable formal = callCmd.Proc.InParams[i]; + string domainName = FindDomainName(formal); + if (domainName == null) continue; + IdentifierExpr actual = callCmd.Ins[i] as IdentifierExpr; + if (parallelCallInvars.Contains(actual.Decl)) + { + Error(node, string.Format("Linear variable {0} can occur only once as an input parameter of a parallel call", actual.Decl.Name)); + } + else + { + parallelCallInvars.Add(actual.Decl); + } + } + } + return base.VisitParCallCmd(node); + } + + public override Requires VisitRequires(Requires requires) + { + return requires; + } + + public override Ensures VisitEnsures(Ensures ensures) + { + return ensures; + } + + public IEnumerable<Variable> AvailableLinearVars(Absy absy) + { + if (availableLinearVars.ContainsKey(absy)) + { + return availableLinearVars[absy]; + } + else + { + return new HashSet<Variable>(); + } + } + + private void AddDisjointnessExpr(List<Cmd> newCmds, Absy absy, Dictionary<string, Variable> domainNameToInputVar) + { + Dictionary<string, HashSet<Variable>> domainNameToScope = new Dictionary<string, HashSet<Variable>>(); + foreach (var domainName in linearDomains.Keys) + { + domainNameToScope[domainName] = new HashSet<Variable>(); + } + foreach (Variable v in AvailableLinearVars(absy)) + { + var domainName = FindDomainName(v); + domainNameToScope[domainName].Add(v); + } + foreach (Variable v in globalVarToDomainName.Keys) + { + var domainName = FindDomainName(v); + domainNameToScope[domainName].Add(v); + } + foreach (string domainName in linearDomains.Keys) + { + newCmds.Add(new AssumeCmd(Token.NoToken, DisjointnessExpr(domainName, domainNameToInputVar[domainName], domainNameToScope[domainName]))); + } + } + + public void Transform() + { + foreach (var impl in program.Implementations) + { + Dictionary<string, Variable> domainNameToInputVar = new Dictionary<string, Variable>(); + foreach (string domainName in linearDomains.Keys) + { + var domain = linearDomains[domainName]; + Formal f = new Formal( + Token.NoToken, + new TypedIdent(Token.NoToken, + "linear_" + domainName + "_in", + new MapType(Token.NoToken, new List<TypeVariable>(), + new List<Type> { domain.elementType }, Type.Bool)), true); + impl.InParams.Add(f); + domainNameToInputVar[domainName] = f; + } + + foreach (Block b in impl.Blocks) + { + List<Cmd> newCmds = new List<Cmd>(); + for (int i = 0; i < b.Cmds.Count; i++) + { + Cmd cmd = b.Cmds[i]; + newCmds.Add(cmd); + if (cmd is CallCmd) + { + CallCmd callCmd = cmd as CallCmd; + if (callCmd.IsAsync) + { + foreach (var domainName in linearDomains.Keys) + { + var domain = linearDomains[domainName]; + var expr = new NAryExpr(Token.NoToken, new FunctionCall(domain.mapConstBool), new List<Expr> { Expr.False }); + expr.Resolve(new ResolutionContext(null)); + expr.Typecheck(new TypecheckingContext(null)); + callCmd.Ins.Add(expr); + } + } + else + { + Dictionary<string, Expr> domainNameToExpr = new Dictionary<string, Expr>(); + foreach (var domainName in linearDomains.Keys) + { + domainNameToExpr[domainName] = Expr.Ident(domainNameToInputVar[domainName]); + } + foreach (Variable v in AvailableLinearVars(callCmd)) + { + var domainName = FindDomainName(v); + var domain = linearDomains[domainName]; + if (!domain.collectors.ContainsKey(v.TypedIdent.Type)) continue; + Expr ie = new NAryExpr(Token.NoToken, new FunctionCall(domain.collectors[v.TypedIdent.Type]), new List<Expr> { Expr.Ident(v) }); + var expr = new NAryExpr(Token.NoToken, new FunctionCall(domain.mapOrBool), new List<Expr> { ie, domainNameToExpr[domainName] }); + expr.Resolve(new ResolutionContext(null)); + expr.Typecheck(new TypecheckingContext(null)); + domainNameToExpr[domainName] = expr; + } + foreach (var domainName in linearDomains.Keys) + { + callCmd.Ins.Add(domainNameToExpr[domainName]); + } + } + } + else if (cmd is ParCallCmd) + { + ParCallCmd parCallCmd = (ParCallCmd)cmd; + foreach (CallCmd callCmd in parCallCmd.CallCmds) + { + foreach (var domainName in linearDomains.Keys) + { + var domain = linearDomains[domainName]; + var expr = new NAryExpr(Token.NoToken, new FunctionCall(domain.mapConstBool), new List<Expr> { Expr.False }); + expr.Resolve(new ResolutionContext(null)); + expr.Typecheck(new TypecheckingContext(null)); + callCmd.Ins.Add(expr); + } + } + } + else if (cmd is YieldCmd) + { + AddDisjointnessExpr(newCmds, cmd, domainNameToInputVar); + } + } + b.Cmds = newCmds; + } + + { + // Loops + impl.PruneUnreachableBlocks(); + impl.ComputePredecessorsForBlocks(); + GraphUtil.Graph<Block> g = Program.GraphFromImpl(impl); + g.ComputeLoops(); + if (g.Reducible) + { + foreach (Block header in g.Headers) + { + List<Cmd> newCmds = new List<Cmd>(); + AddDisjointnessExpr(newCmds, header, domainNameToInputVar); + newCmds.AddRange(header.Cmds); + header.Cmds = newCmds; + } + } + } + } + + foreach (var proc in program.Procedures) + { + Dictionary<string, HashSet<Variable>> domainNameToInputScope = new Dictionary<string, HashSet<Variable>>(); + Dictionary<string, HashSet<Variable>> domainNameToOutputScope = new Dictionary<string, HashSet<Variable>>(); + foreach (var domainName in linearDomains.Keys) + { + domainNameToInputScope[domainName] = new HashSet<Variable>(); + domainNameToOutputScope[domainName] = new HashSet<Variable>(); + + } + foreach (Variable v in globalVarToDomainName.Keys) + { + var domainName = globalVarToDomainName[v]; + domainNameToInputScope[domainName].Add(v); + domainNameToOutputScope[domainName].Add(v); + } + foreach (Variable v in proc.InParams) + { + var domainName = FindDomainName(v); + if (domainName == null) continue; + if (!this.linearDomains.ContainsKey(domainName)) continue; + domainNameToInputScope[domainName].Add(v); + } + foreach (Variable v in proc.OutParams) + { + var domainName = FindDomainName(v); + if (domainName == null) continue; + if (!this.linearDomains.ContainsKey(domainName)) continue; + domainNameToOutputScope[domainName].Add(v); + } + foreach (var domainName in linearDomains.Keys) + { + proc.Requires.Add(new Requires(true, DisjointnessExpr(domainName, domainNameToInputScope[domainName]))); + var domain = linearDomains[domainName]; + Formal f = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "linear_" + domainName + "_in", new MapType(Token.NoToken, new List<TypeVariable>(), new List<Type> { domain.elementType }, Type.Bool)), true); + proc.InParams.Add(f); + proc.Ensures.Add(new Ensures(true, DisjointnessExpr(domainName, f, domainNameToOutputScope[domainName]))); + } + } + + foreach (LinearDomain domain in linearDomains.Values) + { + program.AddTopLevelDeclaration(domain.mapConstBool); + program.AddTopLevelDeclaration(domain.mapConstInt); + program.AddTopLevelDeclaration(domain.mapEqInt); + program.AddTopLevelDeclaration(domain.mapImpBool); + program.AddTopLevelDeclaration(domain.mapOrBool); + foreach (Axiom axiom in domain.axioms) + { + program.AddTopLevelDeclaration(axiom); + } + } + + //int oldPrintUnstructured = CommandLineOptions.Clo.PrintUnstructured; + //CommandLineOptions.Clo.PrintUnstructured = 1; + //PrintBplFile("lsd.bpl", program, false, false); + //CommandLineOptions.Clo.PrintUnstructured = oldPrintUnstructured; + } + + private Expr SubsetExpr(LinearDomain domain, Expr ie, Variable partition, int partitionCount) + { + Expr e = new NAryExpr(Token.NoToken, new FunctionCall(domain.mapConstInt), new List<Expr> { new LiteralExpr(Token.NoToken, Microsoft.Basetypes.BigNum.FromInt(partitionCount)) }); + e = new NAryExpr(Token.NoToken, new FunctionCall(domain.mapEqInt), new List<Expr> { Expr.Ident(partition), e }); + e = new NAryExpr(Token.NoToken, new FunctionCall(domain.mapImpBool), new List<Expr> { ie, e }); + e = Expr.Eq(e, new NAryExpr(Token.NoToken, new FunctionCall(domain.mapConstBool), new List<Expr> { Expr.True })); + return e; + } + + private Expr SubsetExprs(LinearDomain domain, HashSet<Variable> scope, Variable partition, int count, Expr expr) + { + foreach (Variable v in scope) + { + if (!domain.collectors.ContainsKey(v.TypedIdent.Type)) continue; + Expr ie = new NAryExpr(Token.NoToken, new FunctionCall(domain.collectors[v.TypedIdent.Type]), new List<Expr> { Expr.Ident(v) }); + expr = Expr.And(SubsetExpr(domain, ie, partition, count), expr); + count++; + } + expr = new ExistsExpr(Token.NoToken, new List<Variable> { partition }, expr); + expr.Resolve(new ResolutionContext(null)); + expr.Typecheck(new TypecheckingContext(null)); + return expr; + } + + public Expr DisjointnessExpr(string domainName, Variable inputVar, HashSet<Variable> scope) + { + LinearDomain domain = linearDomains[domainName]; + BoundVariable partition = new BoundVariable(Token.NoToken, new TypedIdent(Token.NoToken, string.Format("partition_{0}", domainName), new MapType(Token.NoToken, new List<TypeVariable>(), new List<Type> { domain.elementType }, Microsoft.Boogie.Type.Int))); + return SubsetExprs(domain, scope, partition, 1, SubsetExpr(domain, Expr.Ident(inputVar), partition, 0)); + } + + public Expr DisjointnessExpr(string domainName, HashSet<Variable> scope) + { + LinearDomain domain = linearDomains[domainName]; + BoundVariable partition = new BoundVariable(Token.NoToken, new TypedIdent(Token.NoToken, string.Format("partition_{0}", domainName), new MapType(Token.NoToken, new List<TypeVariable>(), new List<Type> { domain.elementType }, Microsoft.Boogie.Type.Int))); + return SubsetExprs(domain, scope, partition, 0, Expr.True); + } + } + + public class LinearQualifier + { + public string domainName; + public LinearKind kind; + public LinearQualifier(string domainName, LinearKind kind) + { + this.domainName = domainName; + this.kind = kind; + } + } + + public class LinearDomain + { + public Function mapEqInt; + public Function mapConstInt; + public Function mapOrBool; + public Function mapImpBool; + public Function mapConstBool; + public List<Axiom> axioms; + public Type elementType; + public Dictionary<Type, Function> collectors; + + public LinearDomain(Program program, string domainName, Dictionary<Type, Function> collectors) + { + this.axioms = new List<Axiom>(); + this.collectors = collectors; + MapType setType = (MapType)collectors.First().Value.OutParams[0].TypedIdent.Type; + this.elementType = setType.Arguments[0]; + MapType mapTypeBool = new MapType(Token.NoToken, new List<TypeVariable>(), new List<Type> { this.elementType }, Type.Bool); + MapType mapTypeInt = new MapType(Token.NoToken, new List<TypeVariable>(), new List<Type> { this.elementType }, Type.Int); + this.mapOrBool = new Function(Token.NoToken, "linear_" + domainName + "_MapOr", + new List<Variable> { new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "a", mapTypeBool), true), + new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "b", mapTypeBool), true) }, + new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "c", mapTypeBool), false)); + if (CommandLineOptions.Clo.UseArrayTheory) + { + this.mapOrBool.AddAttribute("builtin", "MapOr"); + } + else + { + BoundVariable a = new BoundVariable(Token.NoToken, new TypedIdent(Token.NoToken, "a", mapTypeBool)); + IdentifierExpr aie = Expr.Ident(a); + BoundVariable b = new BoundVariable(Token.NoToken, new TypedIdent(Token.NoToken, "b", mapTypeBool)); + IdentifierExpr bie = Expr.Ident(b); + BoundVariable x = new BoundVariable(Token.NoToken, new TypedIdent(Token.NoToken, "x", elementType)); + IdentifierExpr xie = Expr.Ident(x); + var mapApplTerm = new NAryExpr(Token.NoToken, new FunctionCall(mapOrBool), new List<Expr> { aie, bie } ); + var lhsTerm = new NAryExpr(Token.NoToken, new MapSelect(Token.NoToken, 1), new List<Expr> { mapApplTerm, xie } ); + var rhsTerm = Expr.Or(new NAryExpr(Token.NoToken, new MapSelect(Token.NoToken, 1), new List<Expr> { aie, xie } ), + new NAryExpr(Token.NoToken, new MapSelect(Token.NoToken, 1), new List<Expr> { bie, xie} )); + var axiomExpr = new ForallExpr(Token.NoToken, new List<TypeVariable>(), new List<Variable> { a, b }, null, + new Trigger(Token.NoToken, true, new List<Expr> { mapApplTerm }), + new ForallExpr(Token.NoToken, new List<Variable> { x }, Expr.Binary(BinaryOperator.Opcode.Eq, lhsTerm, rhsTerm))); + axiomExpr.Typecheck(new TypecheckingContext(null)); + axioms.Add(new Axiom(Token.NoToken, axiomExpr)); + } + + this.mapImpBool = new Function(Token.NoToken, "linear_" + domainName + "_MapImp", + new List<Variable> { new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "a", mapTypeBool), true), + new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "b", mapTypeBool), true) }, + new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "c", mapTypeBool), false)); + if (CommandLineOptions.Clo.UseArrayTheory) + { + this.mapImpBool.AddAttribute("builtin", "MapImp"); + } + else + { + BoundVariable a = new BoundVariable(Token.NoToken, new TypedIdent(Token.NoToken, "a", mapTypeBool)); + IdentifierExpr aie = Expr.Ident(a); + BoundVariable b = new BoundVariable(Token.NoToken, new TypedIdent(Token.NoToken, "b", mapTypeBool)); + IdentifierExpr bie = Expr.Ident(b); + BoundVariable x = new BoundVariable(Token.NoToken, new TypedIdent(Token.NoToken, "x", elementType)); + IdentifierExpr xie = Expr.Ident(x); + var mapApplTerm = new NAryExpr(Token.NoToken, new FunctionCall(mapImpBool), new List<Expr> { aie, bie }); + var lhsTerm = new NAryExpr(Token.NoToken, new MapSelect(Token.NoToken, 1), new List<Expr> { mapApplTerm, xie }); + var rhsTerm = Expr.Imp(new NAryExpr(Token.NoToken, new MapSelect(Token.NoToken, 1), new List<Expr> { aie, xie }), + new NAryExpr(Token.NoToken, new MapSelect(Token.NoToken, 1), new List<Expr> { bie, xie })); + var axiomExpr = new ForallExpr(Token.NoToken, new List<TypeVariable>(), new List<Variable> { a, b }, null, + new Trigger(Token.NoToken, true, new List<Expr> { mapApplTerm }), + new ForallExpr(Token.NoToken, new List<Variable> { x }, Expr.Binary(BinaryOperator.Opcode.Eq, lhsTerm, rhsTerm))); + axiomExpr.Typecheck(new TypecheckingContext(null)); + axioms.Add(new Axiom(Token.NoToken, axiomExpr)); + } + + this.mapConstBool = new Function(Token.NoToken, "linear_" + domainName + "_MapConstBool", + new List<Variable> { new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "b", Type.Bool), true) }, + new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "c", mapTypeBool), false)); + if (CommandLineOptions.Clo.UseArrayTheory) + { + this.mapConstBool.AddAttribute("builtin", "MapConst"); + } + else + { + BoundVariable x = new BoundVariable(Token.NoToken, new TypedIdent(Token.NoToken, "x", elementType)); + IdentifierExpr xie = Expr.Ident(x); + var trueTerm = new NAryExpr(Token.NoToken, new MapSelect(Token.NoToken, 1), + new List<Expr> { new NAryExpr(Token.NoToken, new FunctionCall(mapConstBool), new List<Expr> { Expr.True }), xie }); + var trueAxiomExpr = new ForallExpr(Token.NoToken, new List<Variable> { x }, trueTerm); + trueAxiomExpr.Typecheck(new TypecheckingContext(null)); + axioms.Add(new Axiom(Token.NoToken, trueAxiomExpr)); + var falseTerm = new NAryExpr(Token.NoToken, new MapSelect(Token.NoToken, 1), + new List<Expr> { new NAryExpr(Token.NoToken, new FunctionCall(mapConstBool), new List<Expr> { Expr.False }), xie }); + var falseAxiomExpr = new ForallExpr(Token.NoToken, new List<Variable> { x }, Expr.Unary(Token.NoToken, UnaryOperator.Opcode.Not, falseTerm)); + falseAxiomExpr.Typecheck(new TypecheckingContext(null)); + axioms.Add(new Axiom(Token.NoToken, falseAxiomExpr)); + } + + this.mapEqInt = new Function(Token.NoToken, "linear_" + domainName + "_MapEq", + new List<Variable> { new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "a", mapTypeInt), true), + new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "b", mapTypeInt), true) }, + new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "c", mapTypeBool), false)); + if (CommandLineOptions.Clo.UseArrayTheory) + { + this.mapEqInt.AddAttribute("builtin", "MapEq"); + } + else + { + BoundVariable a = new BoundVariable(Token.NoToken, new TypedIdent(Token.NoToken, "a", mapTypeInt)); + IdentifierExpr aie = Expr.Ident(a); + BoundVariable b = new BoundVariable(Token.NoToken, new TypedIdent(Token.NoToken, "b", mapTypeInt)); + IdentifierExpr bie = Expr.Ident(b); + BoundVariable x = new BoundVariable(Token.NoToken, new TypedIdent(Token.NoToken, "x", elementType)); + IdentifierExpr xie = Expr.Ident(x); + var mapApplTerm = new NAryExpr(Token.NoToken, new FunctionCall(mapEqInt), new List<Expr> { aie, bie }); + var lhsTerm = new NAryExpr(Token.NoToken, new MapSelect(Token.NoToken, 1), new List<Expr> { mapApplTerm, xie }); + var rhsTerm = Expr.Eq(new NAryExpr(Token.NoToken, new MapSelect(Token.NoToken, 1), new List<Expr> { aie, xie }), + new NAryExpr(Token.NoToken, new MapSelect(Token.NoToken, 1), new List<Expr> { bie, xie })); + var axiomExpr = new ForallExpr(Token.NoToken, new List<TypeVariable>(), new List<Variable> { a, b }, null, + new Trigger(Token.NoToken, true, new List<Expr> { mapApplTerm }), + new ForallExpr(Token.NoToken, new List<Variable> { x }, Expr.Binary(BinaryOperator.Opcode.Eq, lhsTerm, rhsTerm))); + axiomExpr.Typecheck(new TypecheckingContext(null)); + axioms.Add(new Axiom(Token.NoToken, axiomExpr)); + } + + this.mapConstInt = new Function(Token.NoToken, "linear_" + domainName + "_MapConstInt", + new List<Variable> { new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "b", Type.Int), true) }, + new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "c", mapTypeInt), false)); + if (CommandLineOptions.Clo.UseArrayTheory) + { + this.mapConstInt.AddAttribute("builtin", "MapConst"); + } + else + { + BoundVariable a = new BoundVariable(Token.NoToken, new TypedIdent(Token.NoToken, "a", Type.Int)); + IdentifierExpr aie = Expr.Ident(a); + BoundVariable x = new BoundVariable(Token.NoToken, new TypedIdent(Token.NoToken, "x", elementType)); + IdentifierExpr xie = Expr.Ident(x); + var lhsTerm = new NAryExpr(Token.NoToken, new MapSelect(Token.NoToken, 1), new List<Expr> { new NAryExpr(Token.NoToken, new FunctionCall(mapConstInt), new List<Expr> { aie }), xie }); + var axiomExpr = new ForallExpr(Token.NoToken, new List<Variable> { a, x }, Expr.Binary(BinaryOperator.Opcode.Eq, lhsTerm, aie)); + axiomExpr.Typecheck(new TypecheckingContext(null)); + axioms.Add(new Axiom(Token.NoToken, axiomExpr)); + } + + foreach (var axiom in axioms) + { + axiom.Expr.Resolve(new ResolutionContext(null)); + axiom.Expr.Typecheck(new TypecheckingContext(null)); + } + } + } +} diff --git a/Source/Concurrency/MoverCheck.cs b/Source/Concurrency/MoverCheck.cs index 971e7271..732bcaa4 100644 --- a/Source/Concurrency/MoverCheck.cs +++ b/Source/Concurrency/MoverCheck.cs @@ -1,649 +1,673 @@ -using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Diagnostics.Contracts;
-using System.Diagnostics;
-
-namespace Microsoft.Boogie
-{
- public class MoverCheck
- {
- LinearTypeChecker linearTypeChecker;
- MoverTypeChecker moverTypeChecker;
- List<Declaration> decls;
- HashSet<Tuple<AtomicActionInfo, AtomicActionInfo>> commutativityCheckerCache;
- HashSet<Tuple<AtomicActionInfo, AtomicActionInfo>> gatePreservationCheckerCache;
- HashSet<Tuple<AtomicActionInfo, AtomicActionInfo>> failurePreservationCheckerCache;
- private MoverCheck(LinearTypeChecker linearTypeChecker, MoverTypeChecker moverTypeChecker, List<Declaration> decls)
- {
- this.linearTypeChecker = linearTypeChecker;
- this.moverTypeChecker = moverTypeChecker;
- this.decls = decls;
- this.commutativityCheckerCache = new HashSet<Tuple<AtomicActionInfo, AtomicActionInfo>>();
- this.gatePreservationCheckerCache = new HashSet<Tuple<AtomicActionInfo, AtomicActionInfo>>();
- this.failurePreservationCheckerCache = new HashSet<Tuple<AtomicActionInfo, AtomicActionInfo>>();
- }
-
- public static void AddCheckers(LinearTypeChecker linearTypeChecker, MoverTypeChecker moverTypeChecker, List<Declaration> decls)
- {
- if (moverTypeChecker.procToActionInfo.Count == 0)
- return;
-
- List<ActionInfo> sortedByCreatedLayerNum = new List<ActionInfo>(moverTypeChecker.procToActionInfo.Values.Where(x => x is AtomicActionInfo));
- sortedByCreatedLayerNum.Sort((x, y) => { return (x.createdAtLayerNum == y.createdAtLayerNum) ? 0 : (x.createdAtLayerNum < y.createdAtLayerNum) ? -1 : 1; });
- List<ActionInfo> sortedByAvailableUptoLayerNum = new List<ActionInfo>(moverTypeChecker.procToActionInfo.Values.Where(x => x is AtomicActionInfo));
- sortedByAvailableUptoLayerNum.Sort((x, y) => { return (x.availableUptoLayerNum == y.availableUptoLayerNum) ? 0 : (x.availableUptoLayerNum < y.availableUptoLayerNum) ? -1 : 1; });
-
- Dictionary<int, HashSet<AtomicActionInfo>> pools = new Dictionary<int, HashSet<AtomicActionInfo>>();
- int indexIntoSortedByCreatedLayerNum = 0;
- int indexIntoSortedByAvailableUptoLayerNum = 0;
- HashSet<AtomicActionInfo> currPool = new HashSet<AtomicActionInfo>();
- while (indexIntoSortedByCreatedLayerNum < sortedByCreatedLayerNum.Count)
- {
- var currLayerNum = sortedByCreatedLayerNum[indexIntoSortedByCreatedLayerNum].createdAtLayerNum;
- pools[currLayerNum] = new HashSet<AtomicActionInfo>(currPool);
- while (indexIntoSortedByCreatedLayerNum < sortedByCreatedLayerNum.Count)
- {
- var actionInfo = sortedByCreatedLayerNum[indexIntoSortedByCreatedLayerNum] as AtomicActionInfo;
- if (actionInfo.createdAtLayerNum > currLayerNum) break;
- pools[currLayerNum].Add(actionInfo);
- indexIntoSortedByCreatedLayerNum++;
- }
- while (indexIntoSortedByAvailableUptoLayerNum < sortedByAvailableUptoLayerNum.Count)
- {
- var actionInfo = sortedByAvailableUptoLayerNum[indexIntoSortedByAvailableUptoLayerNum] as AtomicActionInfo;
- if (actionInfo.availableUptoLayerNum > currLayerNum) break;
- pools[currLayerNum].Remove(actionInfo);
- indexIntoSortedByAvailableUptoLayerNum++;
- }
- currPool = pools[currLayerNum];
- }
-
- Program program = moverTypeChecker.program;
- MoverCheck moverChecking = new MoverCheck(linearTypeChecker, moverTypeChecker, decls);
- foreach (int layerNum in pools.Keys)
- {
- foreach (AtomicActionInfo first in pools[layerNum])
- {
- Debug.Assert(first.moverType != MoverType.Top);
- if (first.moverType == MoverType.Atomic)
- continue;
- foreach (AtomicActionInfo second in pools[layerNum])
- {
- if (first.IsRightMover)
- {
- moverChecking.CreateCommutativityChecker(program, first, second);
- moverChecking.CreateGatePreservationChecker(program, second, first);
- }
- if (first.IsLeftMover)
- {
- moverChecking.CreateCommutativityChecker(program, second, first);
- moverChecking.CreateGatePreservationChecker(program, first, second);
- moverChecking.CreateFailurePreservationChecker(program, second, first);
- }
- }
- }
- }
- foreach (ActionInfo actionInfo in moverTypeChecker.procToActionInfo.Values)
- {
- AtomicActionInfo atomicActionInfo = actionInfo as AtomicActionInfo;
- if (atomicActionInfo != null && atomicActionInfo.IsLeftMover && atomicActionInfo.hasAssumeCmd)
- {
- moverChecking.CreateNonBlockingChecker(program, atomicActionInfo);
- }
- }
- }
-
- public sealed class MyDuplicator : Duplicator
- {
- public override Expr VisitIdentifierExpr(IdentifierExpr node)
- {
- IdentifierExpr ret = (IdentifierExpr) base.VisitIdentifierExpr(node);
- if (ret.Decl is GlobalVariable)
- {
- return new OldExpr(Token.NoToken, ret);
- }
- else
- {
- return ret;
- }
- }
- }
-
- public class TransitionRelationComputation
- {
- private Program program;
- private AtomicActionInfo first; // corresponds to that*
- private AtomicActionInfo second; // corresponds to this*
- private Stack<Cmd> cmdStack;
- private List<PathInfo> paths;
- private HashSet<Variable> frame;
- private HashSet<Variable> postExistVars;
-
- public TransitionRelationComputation(Program program, AtomicActionInfo second, HashSet<Variable> frame, HashSet<Variable> postExistVars)
- {
- this.postExistVars = postExistVars;
- this.frame = frame;
- TransitionRelationComputationHelper(program, null, second);
- }
-
- public TransitionRelationComputation(Program program, AtomicActionInfo first, AtomicActionInfo second, HashSet<Variable> frame, HashSet<Variable> postExistVars)
- {
- this.postExistVars = postExistVars;
- this.frame = frame;
- TransitionRelationComputationHelper(program, first, second);
- }
-
- private void TransitionRelationComputationHelper(Program program, AtomicActionInfo first, AtomicActionInfo second)
- {
- this.program = program;
- this.first = first;
- this.second = second;
- this.cmdStack = new Stack<Cmd>();
- this.paths = new List<PathInfo>();
- List<IdentifierExpr> havocVars = new List<IdentifierExpr>();
- this.second.thisOutParams.ForEach(v => havocVars.Add(Expr.Ident(v)));
- this.second.thisAction.LocVars.ForEach(v => havocVars.Add(Expr.Ident(v)));
- if (havocVars.Count > 0)
- {
- HavocCmd havocCmd = new HavocCmd(Token.NoToken, havocVars);
- cmdStack.Push(havocCmd);
- }
- Search(this.second.thisAction.Blocks[0], false);
- }
-
- private void Substitute(Dictionary<Variable, Expr> map, ref List<Expr> pathExprs, ref Dictionary<Variable, Expr> varToExpr)
- {
- Substitution subst = Substituter.SubstitutionFromHashtable(map);
- List<Expr> oldPathExprs = pathExprs;
- pathExprs = new List<Expr>();
- foreach (Expr pathExpr in oldPathExprs)
- {
- pathExprs.Add(Substituter.Apply(subst, pathExpr));
- }
- Dictionary<Variable, Expr> oldVarToExpr = varToExpr;
- varToExpr = new Dictionary<Variable, Expr>();
- foreach (Variable v in oldVarToExpr.Keys)
- {
- varToExpr[v] = Substituter.Apply(subst, oldVarToExpr[v]);
- }
- }
-
- struct PathInfo
- {
- public HashSet<Variable> existsVars;
- public Dictionary<Variable, Expr> varToExpr;
- public List<Expr> pathExprs;
-
- public PathInfo(HashSet<Variable> existsVars, Dictionary<Variable, Expr> varToExpr, List<Expr> pathExprs)
- {
- this.existsVars = existsVars;
- this.varToExpr = varToExpr;
- this.pathExprs = pathExprs;
- }
- }
-
- private void FlattenAnd(Expr x, List<Expr> xs)
- {
- NAryExpr naryExpr = x as NAryExpr;
- if (naryExpr != null && naryExpr.Fun.FunctionName == "&&")
- {
- FlattenAnd(naryExpr.Args[0], xs);
- FlattenAnd(naryExpr.Args[1], xs);
- }
- else
- {
- xs.Add(x);
- }
- }
-
- private void AddPath()
- {
- HashSet<Variable> existsVars = new HashSet<Variable>();
- Dictionary<Variable, Expr> varToExpr = new Dictionary<Variable, Expr>();
- foreach (Variable v in frame)
- {
- varToExpr[v] = Expr.Ident(v);
- }
- if (first != null)
- {
- foreach (Variable v in first.thatOutParams)
- {
- varToExpr[v] = Expr.Ident(v);
- }
- }
- foreach (Variable v in second.thisOutParams)
- {
- varToExpr[v] = Expr.Ident(v);
- }
- List<Expr> pathExprs = new List<Expr>();
- int boundVariableCount = 0;
- foreach (Cmd cmd in cmdStack)
- {
- if (cmd is AssumeCmd)
- {
- AssumeCmd assumeCmd = cmd as AssumeCmd;
- FlattenAnd(assumeCmd.Expr, pathExprs);
- }
- else if (cmd is AssignCmd)
- {
- AssignCmd assignCmd = (cmd as AssignCmd).AsSimpleAssignCmd;
- Dictionary<Variable, Expr> map = new Dictionary<Variable, Expr>();
- for (int k = 0; k < assignCmd.Lhss.Count; k++)
- {
- map[assignCmd.Lhss[k].DeepAssignedVariable] = assignCmd.Rhss[k];
- }
- Substitute(map, ref pathExprs, ref varToExpr);
- }
- else if (cmd is HavocCmd)
- {
- HavocCmd havocCmd = cmd as HavocCmd;
- Dictionary<Variable, Expr> map = new Dictionary<Variable, Expr>();
- foreach (IdentifierExpr ie in havocCmd.Vars)
- {
- BoundVariable bv = new BoundVariable(Token.NoToken, new TypedIdent(Token.NoToken, "#tmp_" + boundVariableCount++, ie.Decl.TypedIdent.Type));
- map[ie.Decl] = Expr.Ident(bv);
- existsVars.Add(bv);
- }
- Substitute(map, ref pathExprs, ref varToExpr);
- }
- else
- {
- Debug.Assert(false);
- }
- }
- paths.Add(new PathInfo(existsVars, varToExpr, pathExprs));
- }
-
- private Expr CalculatePathCondition(PathInfo path)
- {
- Expr returnExpr = Expr.True;
-
- HashSet<Variable> existsVars = path.existsVars;
- Dictionary<Variable, Expr> existsMap = new Dictionary<Variable, Expr>();
-
- Dictionary<Variable, Expr> varToExpr = path.varToExpr;
- foreach (Variable v in varToExpr.Keys)
- {
- if (postExistVars.Contains(v)) continue;
- IdentifierExpr ie = varToExpr[v] as IdentifierExpr;
- if (ie != null && !existsMap.ContainsKey(ie.Decl) && existsVars.Contains(ie.Decl))
- {
- existsMap[ie.Decl] = Expr.Ident(v);
- existsVars.Remove(ie.Decl);
- }
- else
- {
- returnExpr = Expr.And(returnExpr, Expr.Eq(Expr.Ident(v), (new MyDuplicator()).VisitExpr(varToExpr[v])));
- returnExpr.Type = Type.Bool;
- }
- }
-
- List<Expr> pathExprs = new List<Expr>();
- path.pathExprs.ForEach(x => pathExprs.Add((new MyDuplicator()).VisitExpr(x)));
- foreach (Expr x in pathExprs)
- {
- Variable boundVar;
- Expr boundVarExpr;
- if (InferSubstitution(x, out boundVar, out boundVarExpr) && existsVars.Contains(boundVar))
- {
- existsMap[boundVar] = boundVarExpr;
- existsVars.Remove(boundVar);
- }
- else
- {
- returnExpr = Expr.And(returnExpr, x);
- returnExpr.Type = Type.Bool;
- }
- }
-
- returnExpr = Substituter.Apply(Substituter.SubstitutionFromHashtable(existsMap), returnExpr);
- if (existsVars.Count > 0)
- {
- returnExpr = new ExistsExpr(Token.NoToken, new List<Variable>(existsVars), returnExpr);
- }
- return returnExpr;
- }
-
- bool InferSubstitution(Expr x, out Variable var, out Expr expr)
- {
- var = null;
- expr = null;
- NAryExpr naryExpr = x as NAryExpr;
- if (naryExpr == null || naryExpr.Fun.FunctionName != "==")
- {
- return false;
- }
- IdentifierExpr arg0 = naryExpr.Args[0] as IdentifierExpr;
- if (arg0 != null && arg0.Decl is BoundVariable)
- {
- var = arg0.Decl;
- expr = naryExpr.Args[1];
- return true;
- }
- IdentifierExpr arg1 = naryExpr.Args[1] as IdentifierExpr;
- if (arg1 != null && arg1.Decl is BoundVariable)
- {
- var = arg1.Decl;
- expr = naryExpr.Args[0];
- return true;
- }
- return false;
- }
-
- public Expr TransitionRelationCompute()
- {
- Expr transitionRelation = Expr.False;
- foreach (PathInfo path in paths)
- {
- transitionRelation = Expr.Or(transitionRelation, CalculatePathCondition(path));
- }
- ResolutionContext rc = new ResolutionContext(null);
- rc.StateMode = ResolutionContext.State.Two;
- transitionRelation.Resolve(rc);
- transitionRelation.Typecheck(new TypecheckingContext(null));
- return transitionRelation;
- }
-
- private void Search(Block b, bool inFirst)
- {
- int pathSizeAtEntry = cmdStack.Count;
- foreach (Cmd cmd in b.Cmds)
- {
- cmdStack.Push(cmd);
- }
- if (b.TransferCmd is ReturnCmd)
- {
- if (first == null || inFirst)
- {
- AddPath();
- }
- else
- {
- List<IdentifierExpr> havocVars = new List<IdentifierExpr>();
- first.thatOutParams.ForEach(v => havocVars.Add(Expr.Ident(v)));
- first.thatAction.LocVars.ForEach(v => havocVars.Add(Expr.Ident(v)));
- if (havocVars.Count > 0)
- {
- HavocCmd havocCmd = new HavocCmd(Token.NoToken, havocVars);
- cmdStack.Push(havocCmd);
- }
- Search(first.thatAction.Blocks[0], true);
- }
- }
- else
- {
- GotoCmd gotoCmd = b.TransferCmd as GotoCmd;
- foreach (Block target in gotoCmd.labelTargets)
- {
- Search(target, inFirst);
- }
- }
- Debug.Assert(cmdStack.Count >= pathSizeAtEntry);
- while (cmdStack.Count > pathSizeAtEntry)
- {
- cmdStack.Pop();
- }
- }
- }
-
- private static List<Block> CloneBlocks(List<Block> blocks)
- {
- Dictionary<Block, Block> blockMap = new Dictionary<Block, Block>();
- List<Block> otherBlocks = new List<Block>();
- foreach (Block block in blocks)
- {
- List<Cmd> otherCmds = new List<Cmd>();
- foreach (Cmd cmd in block.Cmds)
- {
- otherCmds.Add(cmd);
- }
- Block otherBlock = new Block();
- otherBlock.Cmds = otherCmds;
- otherBlock.Label = block.Label;
- otherBlocks.Add(otherBlock);
- blockMap[block] = otherBlock;
- }
- foreach (Block block in blocks)
- {
- if (block.TransferCmd is ReturnCmd) continue;
- List<Block> otherGotoCmdLabelTargets = new List<Block>();
- List<string> otherGotoCmdLabelNames = new List<string>();
- GotoCmd gotoCmd = block.TransferCmd as GotoCmd;
- foreach (Block target in gotoCmd.labelTargets)
- {
- otherGotoCmdLabelTargets.Add(blockMap[target]);
- otherGotoCmdLabelNames.Add(blockMap[target].Label);
- }
- blockMap[block].TransferCmd = new GotoCmd(block.TransferCmd.tok, otherGotoCmdLabelNames, otherGotoCmdLabelTargets);
- }
- return otherBlocks;
- }
-
- private List<Requires> DisjointnessRequires(Program program, AtomicActionInfo first, AtomicActionInfo second, HashSet<Variable> frame)
- {
- List<Requires> requires = new List<Requires>();
- Dictionary<string, HashSet<Variable>> domainNameToScope = new Dictionary<string, HashSet<Variable>>();
- foreach (var domainName in linearTypeChecker.linearDomains.Keys)
- {
- domainNameToScope[domainName] = new HashSet<Variable>();
- }
- foreach (Variable v in frame)
- {
- var domainName = linearTypeChecker.FindDomainName(v);
- if (domainName == null) continue;
- if (!linearTypeChecker.linearDomains.ContainsKey(domainName)) continue;
- domainNameToScope[domainName].Add(v);
- }
- if (first != null)
- {
- foreach (Variable v in first.thatInParams)
- {
- var domainName = linearTypeChecker.FindDomainName(v);
- if (domainName == null) continue;
- if (!linearTypeChecker.linearDomains.ContainsKey(domainName)) continue;
- domainNameToScope[domainName].Add(v);
- }
- }
- foreach (Variable v in second.thisInParams)
- {
- var domainName = linearTypeChecker.FindDomainName(v);
- if (domainName == null) continue;
- if (!linearTypeChecker.linearDomains.ContainsKey(domainName)) continue;
- domainNameToScope[domainName].Add(v);
- }
- foreach (string domainName in domainNameToScope.Keys)
- {
- requires.Add(new Requires(false, linearTypeChecker.DisjointnessExpr(domainName, domainNameToScope[domainName])));
- }
- return requires;
- }
-
- private void CreateCommutativityChecker(Program program, AtomicActionInfo first, AtomicActionInfo second)
- {
- if (first == second && first.thatInParams.Count == 0 && first.thatOutParams.Count == 0)
- return;
- if (first.CommutesWith(second))
- return;
- Tuple<AtomicActionInfo, AtomicActionInfo> actionPair = new Tuple<AtomicActionInfo, AtomicActionInfo>(first, second);
- if (commutativityCheckerCache.Contains(actionPair))
- return;
- commutativityCheckerCache.Add(actionPair);
-
- List<Variable> inputs = new List<Variable>();
- inputs.AddRange(first.thatInParams);
- inputs.AddRange(second.thisInParams);
- List<Variable> outputs = new List<Variable>();
- outputs.AddRange(first.thatOutParams);
- outputs.AddRange(second.thisOutParams);
- List<Variable> locals = new List<Variable>();
- locals.AddRange(first.thatAction.LocVars);
- locals.AddRange(second.thisAction.LocVars);
- List<Block> firstBlocks = CloneBlocks(first.thatAction.Blocks);
- List<Block> secondBlocks = CloneBlocks(second.thisAction.Blocks);
- foreach (Block b in firstBlocks)
- {
- if (b.TransferCmd is ReturnCmd)
- {
- List<Block> bs = new List<Block>();
- bs.Add(secondBlocks[0]);
- List<string> ls = new List<string>();
- ls.Add(secondBlocks[0].Label);
- b.TransferCmd = new GotoCmd(Token.NoToken, ls, bs);
- }
- }
- List<Block> blocks = new List<Block>();
- blocks.AddRange(firstBlocks);
- blocks.AddRange(secondBlocks);
- HashSet<Variable> frame = new HashSet<Variable>();
- frame.UnionWith(first.gateUsedGlobalVars);
- frame.UnionWith(first.actionUsedGlobalVars);
- frame.UnionWith(second.gateUsedGlobalVars);
- frame.UnionWith(second.actionUsedGlobalVars);
- List<Requires> requires = DisjointnessRequires(program, first, second, frame);
- foreach (AssertCmd assertCmd in first.thatGate)
- requires.Add(new Requires(false, assertCmd.Expr));
- foreach (AssertCmd assertCmd in second.thisGate)
- requires.Add(new Requires(false, assertCmd.Expr));
- List<Ensures> ensures = new List<Ensures>();
- Expr transitionRelation = (new TransitionRelationComputation(program, first, second, frame, new HashSet<Variable>())).TransitionRelationCompute();
- Ensures ensureCheck = new Ensures(false, transitionRelation);
- ensureCheck.ErrorData = string.Format("Commutativity check between {0} and {1} failed", first.proc.Name, second.proc.Name);
- ensures.Add(ensureCheck);
- string checkerName = string.Format("CommutativityChecker_{0}_{1}", first.proc.Name, second.proc.Name);
- List<IdentifierExpr> globalVars = new List<IdentifierExpr>();
- moverTypeChecker.SharedVariables.Iter(x => globalVars.Add(Expr.Ident(x)));
- Procedure proc = new Procedure(Token.NoToken, checkerName, new List<TypeVariable>(), inputs, outputs, requires, globalVars, ensures);
- Implementation impl = new Implementation(Token.NoToken, checkerName, new List<TypeVariable>(), inputs, outputs, locals, blocks);
- impl.Proc = proc;
- this.decls.Add(impl);
- this.decls.Add(proc);
- }
-
- private void CreateGatePreservationChecker(Program program, AtomicActionInfo first, AtomicActionInfo second)
- {
- if (first.gateUsedGlobalVars.Intersect(second.modifiedGlobalVars).Count() == 0)
- return;
- Tuple<AtomicActionInfo, AtomicActionInfo> actionPair = new Tuple<AtomicActionInfo, AtomicActionInfo>(first, second);
- if (gatePreservationCheckerCache.Contains(actionPair))
- return;
- gatePreservationCheckerCache.Add(actionPair);
-
- List<Variable> inputs = new List<Variable>();
- inputs.AddRange(first.thatInParams);
- inputs.AddRange(second.thisInParams);
- List<Variable> outputs = new List<Variable>();
- outputs.AddRange(first.thatOutParams);
- outputs.AddRange(second.thisOutParams);
- List<Variable> locals = new List<Variable>();
- locals.AddRange(second.thisAction.LocVars);
- List<Block> secondBlocks = CloneBlocks(second.thisAction.Blocks);
- HashSet<Variable> frame = new HashSet<Variable>();
- frame.UnionWith(first.gateUsedGlobalVars);
- frame.UnionWith(second.gateUsedGlobalVars);
- frame.UnionWith(second.actionUsedGlobalVars);
- List<Requires> requires = DisjointnessRequires(program, first, second, frame);
- List<Ensures> ensures = new List<Ensures>();
- foreach (AssertCmd assertCmd in first.thatGate)
- {
- requires.Add(new Requires(false, assertCmd.Expr));
- Ensures ensureCheck = new Ensures(assertCmd.tok, false, assertCmd.Expr, null);
- ensureCheck.ErrorData = string.Format("Gate not preserved by {0}", second.proc.Name);
- ensures.Add(ensureCheck);
- }
- foreach (AssertCmd assertCmd in second.thisGate)
- requires.Add(new Requires(false, assertCmd.Expr));
- string checkerName = string.Format("GatePreservationChecker_{0}_{1}", first.proc.Name, second.proc.Name);
- List<IdentifierExpr> globalVars = new List<IdentifierExpr>();
- moverTypeChecker.SharedVariables.Iter(x => globalVars.Add(Expr.Ident(x)));
- Procedure proc = new Procedure(Token.NoToken, checkerName, new List<TypeVariable>(), inputs, outputs, requires, globalVars, ensures);
- Implementation impl = new Implementation(Token.NoToken, checkerName, new List<TypeVariable>(), inputs, outputs, locals, secondBlocks);
- impl.Proc = proc;
- this.decls.Add(impl);
- this.decls.Add(proc);
- }
-
- private void CreateFailurePreservationChecker(Program program, AtomicActionInfo first, AtomicActionInfo second)
- {
- if (first.gateUsedGlobalVars.Intersect(second.modifiedGlobalVars).Count() == 0)
- return;
- Tuple<AtomicActionInfo, AtomicActionInfo> actionPair = new Tuple<AtomicActionInfo, AtomicActionInfo>(first, second);
- if (failurePreservationCheckerCache.Contains(actionPair))
- return;
- failurePreservationCheckerCache.Add(actionPair);
-
- List<Variable> inputs = new List<Variable>();
- inputs.AddRange(first.thatInParams);
- inputs.AddRange(second.thisInParams);
- List<Variable> outputs = new List<Variable>();
- outputs.AddRange(first.thatOutParams);
- outputs.AddRange(second.thisOutParams);
- List<Variable> locals = new List<Variable>();
- locals.AddRange(second.thisAction.LocVars);
- List<Block> secondBlocks = CloneBlocks(second.thisAction.Blocks);
- HashSet<Variable> frame = new HashSet<Variable>();
- frame.UnionWith(first.gateUsedGlobalVars);
- frame.UnionWith(second.gateUsedGlobalVars);
- frame.UnionWith(second.actionUsedGlobalVars);
- List<Requires> requires = DisjointnessRequires(program, first, second, frame);
- Expr gateExpr = Expr.True;
- foreach (AssertCmd assertCmd in first.thatGate)
- {
- gateExpr = Expr.And(gateExpr, assertCmd.Expr);
- gateExpr.Type = Type.Bool;
- }
- gateExpr = Expr.Not(gateExpr);
- gateExpr.Type = Type.Bool;
- requires.Add(new Requires(false, gateExpr));
- List<Ensures> ensures = new List<Ensures>();
- Ensures ensureCheck = new Ensures(false, gateExpr);
- ensureCheck.ErrorData = string.Format("Gate failure of {0} not preserved by {1}", first.proc.Name, second.proc.Name);
- ensures.Add(ensureCheck);
- foreach (AssertCmd assertCmd in second.thisGate)
- requires.Add(new Requires(false, assertCmd.Expr));
- string checkerName = string.Format("FailurePreservationChecker_{0}_{1}", first.proc.Name, second.proc.Name);
- List<IdentifierExpr> globalVars = new List<IdentifierExpr>();
- moverTypeChecker.SharedVariables.Iter(x => globalVars.Add(Expr.Ident(x)));
- Procedure proc = new Procedure(Token.NoToken, checkerName, new List<TypeVariable>(), inputs, outputs, requires, globalVars, ensures);
- Implementation impl = new Implementation(Token.NoToken, checkerName, new List<TypeVariable>(), inputs, outputs, locals, secondBlocks);
- impl.Proc = proc;
- this.decls.Add(impl);
- this.decls.Add(proc);
- }
-
- private void CreateNonBlockingChecker(Program program, AtomicActionInfo second)
- {
- List<Variable> inputs = new List<Variable>();
- inputs.AddRange(second.thisInParams);
-
- HashSet<Variable> frame = new HashSet<Variable>();
- frame.UnionWith(second.gateUsedGlobalVars);
- frame.UnionWith(second.actionUsedGlobalVars);
- List<Requires> requires = DisjointnessRequires(program, null, second, frame);
- foreach (AssertCmd assertCmd in second.thisGate)
- {
- requires.Add(new Requires(false, assertCmd.Expr));
- }
- HashSet<Variable> postExistVars = new HashSet<Variable>();
- postExistVars.UnionWith(frame);
- postExistVars.UnionWith(second.thisOutParams);
- Expr ensuresExpr = (new TransitionRelationComputation(program, second, frame, postExistVars)).TransitionRelationCompute();
- List<Ensures> ensures = new List<Ensures>();
- Ensures ensureCheck = new Ensures(false, ensuresExpr);
- ensureCheck.ErrorData = string.Format("{0} is blocking", second.proc.Name);
- ensures.Add(ensureCheck);
-
- List<Block> blocks = new List<Block>();
- blocks.Add(new Block(Token.NoToken, "L", new List<Cmd>(), new ReturnCmd(Token.NoToken)));
- string checkerName = string.Format("NonBlockingChecker_{0}", second.proc.Name);
- List<IdentifierExpr> globalVars = new List<IdentifierExpr>();
- moverTypeChecker.SharedVariables.Iter(x => globalVars.Add(Expr.Ident(x)));
- Procedure proc = new Procedure(Token.NoToken, checkerName, new List<TypeVariable>(), inputs, new List<Variable>(), requires, globalVars, ensures);
- Implementation impl = new Implementation(Token.NoToken, checkerName, new List<TypeVariable>(), inputs, new List<Variable>(), new List<Variable>(), blocks);
- impl.Proc = proc;
- this.decls.Add(impl);
- this.decls.Add(proc);
- }
- }
+using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Diagnostics.Contracts; +using System.Diagnostics; + +namespace Microsoft.Boogie +{ + public class MoverCheck + { + LinearTypeChecker linearTypeChecker; + CivlTypeChecker civlTypeChecker; + List<Declaration> decls; + HashSet<Tuple<AtomicActionInfo, AtomicActionInfo>> commutativityCheckerCache; + HashSet<Tuple<AtomicActionInfo, AtomicActionInfo>> gatePreservationCheckerCache; + HashSet<Tuple<AtomicActionInfo, AtomicActionInfo>> failurePreservationCheckerCache; + private MoverCheck(LinearTypeChecker linearTypeChecker, CivlTypeChecker civlTypeChecker, List<Declaration> decls) + { + this.linearTypeChecker = linearTypeChecker; + this.civlTypeChecker = civlTypeChecker; + this.decls = decls; + this.commutativityCheckerCache = new HashSet<Tuple<AtomicActionInfo, AtomicActionInfo>>(); + this.gatePreservationCheckerCache = new HashSet<Tuple<AtomicActionInfo, AtomicActionInfo>>(); + this.failurePreservationCheckerCache = new HashSet<Tuple<AtomicActionInfo, AtomicActionInfo>>(); + } + + public static void AddCheckers(LinearTypeChecker linearTypeChecker, CivlTypeChecker civlTypeChecker, List<Declaration> decls) + { + if (civlTypeChecker.procToActionInfo.Count == 0) + return; + + List<ActionInfo> sortedByCreatedLayerNum = new List<ActionInfo>(civlTypeChecker.procToActionInfo.Values.Where(x => x is AtomicActionInfo && !x.isExtern)); + sortedByCreatedLayerNum.Sort((x, y) => { return (x.createdAtLayerNum == y.createdAtLayerNum) ? 0 : (x.createdAtLayerNum < y.createdAtLayerNum) ? -1 : 1; }); + List<ActionInfo> sortedByAvailableUptoLayerNum = new List<ActionInfo>(civlTypeChecker.procToActionInfo.Values.Where(x => x is AtomicActionInfo && !x.isExtern)); + sortedByAvailableUptoLayerNum.Sort((x, y) => { return (x.availableUptoLayerNum == y.availableUptoLayerNum) ? 0 : (x.availableUptoLayerNum < y.availableUptoLayerNum) ? -1 : 1; }); + + Dictionary<int, HashSet<AtomicActionInfo>> pools = new Dictionary<int, HashSet<AtomicActionInfo>>(); + int indexIntoSortedByCreatedLayerNum = 0; + int indexIntoSortedByAvailableUptoLayerNum = 0; + HashSet<AtomicActionInfo> currPool = new HashSet<AtomicActionInfo>(); + while (indexIntoSortedByCreatedLayerNum < sortedByCreatedLayerNum.Count) + { + var currLayerNum = sortedByCreatedLayerNum[indexIntoSortedByCreatedLayerNum].createdAtLayerNum; + pools[currLayerNum] = new HashSet<AtomicActionInfo>(currPool); + while (indexIntoSortedByCreatedLayerNum < sortedByCreatedLayerNum.Count) + { + var actionInfo = sortedByCreatedLayerNum[indexIntoSortedByCreatedLayerNum] as AtomicActionInfo; + if (actionInfo.createdAtLayerNum > currLayerNum) break; + pools[currLayerNum].Add(actionInfo); + indexIntoSortedByCreatedLayerNum++; + } + while (indexIntoSortedByAvailableUptoLayerNum < sortedByAvailableUptoLayerNum.Count) + { + var actionInfo = sortedByAvailableUptoLayerNum[indexIntoSortedByAvailableUptoLayerNum] as AtomicActionInfo; + if (actionInfo.availableUptoLayerNum > currLayerNum) break; + pools[currLayerNum].Remove(actionInfo); + indexIntoSortedByAvailableUptoLayerNum++; + } + currPool = pools[currLayerNum]; + } + + Program program = civlTypeChecker.program; + MoverCheck moverChecking = new MoverCheck(linearTypeChecker, civlTypeChecker, decls); + foreach (int layerNum in pools.Keys) + { + foreach (AtomicActionInfo first in pools[layerNum]) + { + Debug.Assert(first.moverType != MoverType.Top); + if (first.moverType == MoverType.Atomic) + continue; + foreach (AtomicActionInfo second in pools[layerNum]) + { + if (first.IsRightMover) + { + moverChecking.CreateCommutativityChecker(program, first, second); + moverChecking.CreateGatePreservationChecker(program, second, first); + } + if (first.IsLeftMover) + { + moverChecking.CreateCommutativityChecker(program, second, first); + moverChecking.CreateGatePreservationChecker(program, first, second); + moverChecking.CreateFailurePreservationChecker(program, second, first); + } + } + } + } + foreach (AtomicActionInfo atomicActionInfo in sortedByCreatedLayerNum) + { + if (atomicActionInfo.IsLeftMover && atomicActionInfo.hasAssumeCmd) + { + moverChecking.CreateNonBlockingChecker(program, atomicActionInfo); + } + } + } + + public sealed class MyDuplicator : Duplicator + { + public override Expr VisitIdentifierExpr(IdentifierExpr node) + { + IdentifierExpr ret = (IdentifierExpr) base.VisitIdentifierExpr(node); + if (ret.Decl is GlobalVariable) + { + return new OldExpr(Token.NoToken, ret); + } + else + { + return ret; + } + } + } + + public class TransitionRelationComputation + { + private Program program; + private AtomicActionInfo first; // corresponds to that* + private AtomicActionInfo second; // corresponds to this* + private Stack<Cmd> cmdStack; + private List<PathInfo> paths; + private HashSet<Variable> frame; + private HashSet<Variable> postExistVars; + + public TransitionRelationComputation(Program program, AtomicActionInfo second, HashSet<Variable> frame, HashSet<Variable> postExistVars) + { + this.postExistVars = postExistVars; + this.frame = frame; + TransitionRelationComputationHelper(program, null, second); + } + + public TransitionRelationComputation(Program program, AtomicActionInfo first, AtomicActionInfo second, HashSet<Variable> frame, HashSet<Variable> postExistVars) + { + this.postExistVars = postExistVars; + this.frame = frame; + TransitionRelationComputationHelper(program, first, second); + } + + private void TransitionRelationComputationHelper(Program program, AtomicActionInfo first, AtomicActionInfo second) + { + this.program = program; + this.first = first; + this.second = second; + this.cmdStack = new Stack<Cmd>(); + this.paths = new List<PathInfo>(); + List<IdentifierExpr> havocVars = new List<IdentifierExpr>(); + this.second.thisOutParams.ForEach(v => havocVars.Add(Expr.Ident(v))); + this.second.thisAction.LocVars.ForEach(v => havocVars.Add(Expr.Ident(v))); + if (havocVars.Count > 0) + { + HavocCmd havocCmd = new HavocCmd(Token.NoToken, havocVars); + cmdStack.Push(havocCmd); + } + Search(this.second.thisAction.Blocks[0], false); + } + + private void Substitute(Dictionary<Variable, Expr> map, ref List<Expr> pathExprs, ref Dictionary<Variable, Expr> varToExpr) + { + Substitution subst = Substituter.SubstitutionFromHashtable(map); + List<Expr> oldPathExprs = pathExprs; + pathExprs = new List<Expr>(); + foreach (Expr pathExpr in oldPathExprs) + { + pathExprs.Add(Substituter.Apply(subst, pathExpr)); + } + Dictionary<Variable, Expr> oldVarToExpr = varToExpr; + varToExpr = new Dictionary<Variable, Expr>(); + foreach (Variable v in oldVarToExpr.Keys) + { + varToExpr[v] = Substituter.Apply(subst, oldVarToExpr[v]); + } + } + + struct PathInfo + { + public HashSet<Variable> existsVars; + public Dictionary<Variable, Expr> varToExpr; + public List<Expr> pathExprs; + + public PathInfo(HashSet<Variable> existsVars, Dictionary<Variable, Expr> varToExpr, List<Expr> pathExprs) + { + this.existsVars = existsVars; + this.varToExpr = varToExpr; + this.pathExprs = pathExprs; + } + } + + private void FlattenAnd(Expr x, List<Expr> xs) + { + NAryExpr naryExpr = x as NAryExpr; + if (naryExpr != null && naryExpr.Fun.FunctionName == "&&") + { + FlattenAnd(naryExpr.Args[0], xs); + FlattenAnd(naryExpr.Args[1], xs); + } + else + { + xs.Add(x); + } + } + + private void AddPath() + { + HashSet<Variable> existsVars = new HashSet<Variable>(); + Dictionary<Variable, Expr> varToExpr = new Dictionary<Variable, Expr>(); + foreach (Variable v in frame) + { + varToExpr[v] = Expr.Ident(v); + } + if (first != null) + { + foreach (Variable v in first.thatOutParams) + { + varToExpr[v] = Expr.Ident(v); + } + } + foreach (Variable v in second.thisOutParams) + { + varToExpr[v] = Expr.Ident(v); + } + List<Expr> pathExprs = new List<Expr>(); + int boundVariableCount = 0; + foreach (Cmd cmd in cmdStack) + { + if (cmd is AssumeCmd) + { + AssumeCmd assumeCmd = cmd as AssumeCmd; + FlattenAnd(assumeCmd.Expr, pathExprs); + } + else if (cmd is AssignCmd) + { + AssignCmd assignCmd = (cmd as AssignCmd).AsSimpleAssignCmd; + Dictionary<Variable, Expr> map = new Dictionary<Variable, Expr>(); + for (int k = 0; k < assignCmd.Lhss.Count; k++) + { + map[assignCmd.Lhss[k].DeepAssignedVariable] = assignCmd.Rhss[k]; + } + Substitute(map, ref pathExprs, ref varToExpr); + } + else if (cmd is HavocCmd) + { + HavocCmd havocCmd = cmd as HavocCmd; + Dictionary<Variable, Expr> map = new Dictionary<Variable, Expr>(); + foreach (IdentifierExpr ie in havocCmd.Vars) + { + BoundVariable bv = new BoundVariable(Token.NoToken, new TypedIdent(Token.NoToken, "#tmp_" + boundVariableCount++, ie.Decl.TypedIdent.Type)); + map[ie.Decl] = Expr.Ident(bv); + existsVars.Add(bv); + } + Substitute(map, ref pathExprs, ref varToExpr); + } + else + { + Debug.Assert(false); + } + } + paths.Add(new PathInfo(existsVars, varToExpr, pathExprs)); + } + + private Expr CalculatePathCondition(PathInfo path) + { + Expr returnExpr = Expr.True; + + HashSet<Variable> existsVars = path.existsVars; + Dictionary<Variable, Expr> existsMap = new Dictionary<Variable, Expr>(); + + Dictionary<Variable, Expr> varToExpr = path.varToExpr; + foreach (Variable v in varToExpr.Keys) + { + if (postExistVars.Contains(v)) continue; + IdentifierExpr ie = varToExpr[v] as IdentifierExpr; + if (ie != null && !existsMap.ContainsKey(ie.Decl) && existsVars.Contains(ie.Decl)) + { + existsMap[ie.Decl] = Expr.Ident(v); + existsVars.Remove(ie.Decl); + } + else + { + returnExpr = Expr.And(returnExpr, Expr.Eq(Expr.Ident(v), (new MyDuplicator()).VisitExpr(varToExpr[v]))); + returnExpr.Type = Type.Bool; + } + } + + List<Expr> pathExprs = new List<Expr>(); + path.pathExprs.ForEach(x => pathExprs.Add((new MyDuplicator()).VisitExpr(x))); + foreach (Expr x in pathExprs) + { + Variable boundVar; + Expr boundVarExpr; + if (InferSubstitution(x, out boundVar, out boundVarExpr) && existsVars.Contains(boundVar)) + { + existsMap[boundVar] = boundVarExpr; + existsVars.Remove(boundVar); + } + else + { + returnExpr = Expr.And(returnExpr, x); + returnExpr.Type = Type.Bool; + } + } + + returnExpr = Substituter.Apply(Substituter.SubstitutionFromHashtable(existsMap), returnExpr); + if (existsVars.Count > 0) + { + returnExpr = new ExistsExpr(Token.NoToken, new List<Variable>(existsVars), returnExpr); + } + return returnExpr; + } + + bool InferSubstitution(Expr x, out Variable var, out Expr expr) + { + var = null; + expr = null; + NAryExpr naryExpr = x as NAryExpr; + if (naryExpr == null || naryExpr.Fun.FunctionName != "==") + { + return false; + } + IdentifierExpr arg0 = naryExpr.Args[0] as IdentifierExpr; + if (arg0 != null && arg0.Decl is BoundVariable) + { + var = arg0.Decl; + expr = naryExpr.Args[1]; + return true; + } + IdentifierExpr arg1 = naryExpr.Args[1] as IdentifierExpr; + if (arg1 != null && arg1.Decl is BoundVariable) + { + var = arg1.Decl; + expr = naryExpr.Args[0]; + return true; + } + return false; + } + + public Expr TransitionRelationCompute(bool withOriginalInOutVariables = false) + { + Expr transitionRelation = Expr.False; + foreach (PathInfo path in paths) + { + transitionRelation = Expr.Or(transitionRelation, CalculatePathCondition(path)); + } + ResolutionContext rc = new ResolutionContext(null); + rc.StateMode = ResolutionContext.State.Two; + transitionRelation.Resolve(rc); + transitionRelation.Typecheck(new TypecheckingContext(null)); + + if (withOriginalInOutVariables) + { + Dictionary<Variable, Expr> invertedMap = new Dictionary<Variable, Expr>(); + if (first != null) + { + foreach (var x in first.thatMap) + { + invertedMap[((IdentifierExpr)x.Value).Decl] = Expr.Ident(x.Key); + } + } + if (second != null) + { + foreach (var x in second.thisMap) + { + invertedMap[((IdentifierExpr)x.Value).Decl] = Expr.Ident(x.Key); + } + } + Substitution subst = Substituter.SubstitutionFromHashtable(invertedMap); + return Substituter.Apply(subst, transitionRelation); + } + else + { + return transitionRelation; + } + + } + + private void Search(Block b, bool inFirst) + { + int pathSizeAtEntry = cmdStack.Count; + foreach (Cmd cmd in b.Cmds) + { + cmdStack.Push(cmd); + } + if (b.TransferCmd is ReturnCmd) + { + if (first == null || inFirst) + { + AddPath(); + } + else + { + List<IdentifierExpr> havocVars = new List<IdentifierExpr>(); + first.thatOutParams.ForEach(v => havocVars.Add(Expr.Ident(v))); + first.thatAction.LocVars.ForEach(v => havocVars.Add(Expr.Ident(v))); + if (havocVars.Count > 0) + { + HavocCmd havocCmd = new HavocCmd(Token.NoToken, havocVars); + cmdStack.Push(havocCmd); + } + Search(first.thatAction.Blocks[0], true); + } + } + else + { + GotoCmd gotoCmd = b.TransferCmd as GotoCmd; + foreach (Block target in gotoCmd.labelTargets) + { + Search(target, inFirst); + } + } + Debug.Assert(cmdStack.Count >= pathSizeAtEntry); + while (cmdStack.Count > pathSizeAtEntry) + { + cmdStack.Pop(); + } + } + } + + private static List<Block> CloneBlocks(List<Block> blocks) + { + Dictionary<Block, Block> blockMap = new Dictionary<Block, Block>(); + List<Block> otherBlocks = new List<Block>(); + foreach (Block block in blocks) + { + List<Cmd> otherCmds = new List<Cmd>(); + foreach (Cmd cmd in block.Cmds) + { + otherCmds.Add(cmd); + } + Block otherBlock = new Block(); + otherBlock.Cmds = otherCmds; + otherBlock.Label = block.Label; + otherBlocks.Add(otherBlock); + blockMap[block] = otherBlock; + } + foreach (Block block in blocks) + { + if (block.TransferCmd is ReturnCmd) continue; + List<Block> otherGotoCmdLabelTargets = new List<Block>(); + List<string> otherGotoCmdLabelNames = new List<string>(); + GotoCmd gotoCmd = block.TransferCmd as GotoCmd; + foreach (Block target in gotoCmd.labelTargets) + { + otherGotoCmdLabelTargets.Add(blockMap[target]); + otherGotoCmdLabelNames.Add(blockMap[target].Label); + } + blockMap[block].TransferCmd = new GotoCmd(block.TransferCmd.tok, otherGotoCmdLabelNames, otherGotoCmdLabelTargets); + } + return otherBlocks; + } + + private List<Requires> DisjointnessRequires(Program program, AtomicActionInfo first, AtomicActionInfo second, HashSet<Variable> frame) + { + List<Requires> requires = new List<Requires>(); + Dictionary<string, HashSet<Variable>> domainNameToScope = new Dictionary<string, HashSet<Variable>>(); + foreach (var domainName in linearTypeChecker.linearDomains.Keys) + { + domainNameToScope[domainName] = new HashSet<Variable>(); + } + foreach (Variable v in frame) + { + var domainName = linearTypeChecker.FindDomainName(v); + if (domainName == null) continue; + if (!linearTypeChecker.linearDomains.ContainsKey(domainName)) continue; + domainNameToScope[domainName].Add(v); + } + if (first != null) + { + foreach (Variable v in first.thatInParams) + { + var domainName = linearTypeChecker.FindDomainName(v); + if (domainName == null) continue; + if (!linearTypeChecker.linearDomains.ContainsKey(domainName)) continue; + domainNameToScope[domainName].Add(v); + } + } + foreach (Variable v in second.thisInParams) + { + var domainName = linearTypeChecker.FindDomainName(v); + if (domainName == null) continue; + if (!linearTypeChecker.linearDomains.ContainsKey(domainName)) continue; + domainNameToScope[domainName].Add(v); + } + foreach (string domainName in domainNameToScope.Keys) + { + requires.Add(new Requires(false, linearTypeChecker.DisjointnessExpr(domainName, domainNameToScope[domainName]))); + } + return requires; + } + + private void CreateCommutativityChecker(Program program, AtomicActionInfo first, AtomicActionInfo second) + { + if (first == second && first.thatInParams.Count == 0 && first.thatOutParams.Count == 0) + return; + if (first.CommutesWith(second)) + return; + Tuple<AtomicActionInfo, AtomicActionInfo> actionPair = new Tuple<AtomicActionInfo, AtomicActionInfo>(first, second); + if (commutativityCheckerCache.Contains(actionPair)) + return; + commutativityCheckerCache.Add(actionPair); + + List<Variable> inputs = new List<Variable>(); + inputs.AddRange(first.thatInParams); + inputs.AddRange(second.thisInParams); + List<Variable> outputs = new List<Variable>(); + outputs.AddRange(first.thatOutParams); + outputs.AddRange(second.thisOutParams); + List<Variable> locals = new List<Variable>(); + locals.AddRange(first.thatAction.LocVars); + locals.AddRange(second.thisAction.LocVars); + List<Block> firstBlocks = CloneBlocks(first.thatAction.Blocks); + List<Block> secondBlocks = CloneBlocks(second.thisAction.Blocks); + foreach (Block b in firstBlocks) + { + if (b.TransferCmd is ReturnCmd) + { + List<Block> bs = new List<Block>(); + bs.Add(secondBlocks[0]); + List<string> ls = new List<string>(); + ls.Add(secondBlocks[0].Label); + b.TransferCmd = new GotoCmd(Token.NoToken, ls, bs); + } + } + List<Block> blocks = new List<Block>(); + blocks.AddRange(firstBlocks); + blocks.AddRange(secondBlocks); + HashSet<Variable> frame = new HashSet<Variable>(); + frame.UnionWith(first.gateUsedGlobalVars); + frame.UnionWith(first.actionUsedGlobalVars); + frame.UnionWith(second.gateUsedGlobalVars); + frame.UnionWith(second.actionUsedGlobalVars); + List<Requires> requires = DisjointnessRequires(program, first, second, frame); + foreach (AssertCmd assertCmd in first.thatGate) + requires.Add(new Requires(false, assertCmd.Expr)); + foreach (AssertCmd assertCmd in second.thisGate) + requires.Add(new Requires(false, assertCmd.Expr)); + List<Ensures> ensures = new List<Ensures>(); + Expr transitionRelation = (new TransitionRelationComputation(program, first, second, frame, new HashSet<Variable>())).TransitionRelationCompute(); + Ensures ensureCheck = new Ensures(false, transitionRelation); + ensureCheck.ErrorData = string.Format("Commutativity check between {0} and {1} failed", first.proc.Name, second.proc.Name); + ensures.Add(ensureCheck); + string checkerName = string.Format("CommutativityChecker_{0}_{1}", first.proc.Name, second.proc.Name); + List<IdentifierExpr> globalVars = new List<IdentifierExpr>(); + civlTypeChecker.SharedVariables.Iter(x => globalVars.Add(Expr.Ident(x))); + Procedure proc = new Procedure(Token.NoToken, checkerName, new List<TypeVariable>(), inputs, outputs, requires, globalVars, ensures); + Implementation impl = new Implementation(Token.NoToken, checkerName, new List<TypeVariable>(), inputs, outputs, locals, blocks); + impl.Proc = proc; + this.decls.Add(impl); + this.decls.Add(proc); + } + + private void CreateGatePreservationChecker(Program program, AtomicActionInfo first, AtomicActionInfo second) + { + if (first.gateUsedGlobalVars.Intersect(second.modifiedGlobalVars).Count() == 0) + return; + Tuple<AtomicActionInfo, AtomicActionInfo> actionPair = new Tuple<AtomicActionInfo, AtomicActionInfo>(first, second); + if (gatePreservationCheckerCache.Contains(actionPair)) + return; + gatePreservationCheckerCache.Add(actionPair); + + List<Variable> inputs = new List<Variable>(); + inputs.AddRange(first.thatInParams); + inputs.AddRange(second.thisInParams); + List<Variable> outputs = new List<Variable>(); + outputs.AddRange(first.thatOutParams); + outputs.AddRange(second.thisOutParams); + List<Variable> locals = new List<Variable>(); + locals.AddRange(second.thisAction.LocVars); + List<Block> secondBlocks = CloneBlocks(second.thisAction.Blocks); + HashSet<Variable> frame = new HashSet<Variable>(); + frame.UnionWith(first.gateUsedGlobalVars); + frame.UnionWith(second.gateUsedGlobalVars); + frame.UnionWith(second.actionUsedGlobalVars); + List<Requires> requires = DisjointnessRequires(program, first, second, frame); + List<Ensures> ensures = new List<Ensures>(); + foreach (AssertCmd assertCmd in first.thatGate) + { + requires.Add(new Requires(false, assertCmd.Expr)); + Ensures ensureCheck = new Ensures(assertCmd.tok, false, assertCmd.Expr, null); + ensureCheck.ErrorData = string.Format("Gate not preserved by {0}", second.proc.Name); + ensures.Add(ensureCheck); + } + foreach (AssertCmd assertCmd in second.thisGate) + requires.Add(new Requires(false, assertCmd.Expr)); + string checkerName = string.Format("GatePreservationChecker_{0}_{1}", first.proc.Name, second.proc.Name); + List<IdentifierExpr> globalVars = new List<IdentifierExpr>(); + civlTypeChecker.SharedVariables.Iter(x => globalVars.Add(Expr.Ident(x))); + Procedure proc = new Procedure(Token.NoToken, checkerName, new List<TypeVariable>(), inputs, outputs, requires, globalVars, ensures); + Implementation impl = new Implementation(Token.NoToken, checkerName, new List<TypeVariable>(), inputs, outputs, locals, secondBlocks); + impl.Proc = proc; + this.decls.Add(impl); + this.decls.Add(proc); + } + + private void CreateFailurePreservationChecker(Program program, AtomicActionInfo first, AtomicActionInfo second) + { + if (first.gateUsedGlobalVars.Intersect(second.modifiedGlobalVars).Count() == 0) + return; + Tuple<AtomicActionInfo, AtomicActionInfo> actionPair = new Tuple<AtomicActionInfo, AtomicActionInfo>(first, second); + if (failurePreservationCheckerCache.Contains(actionPair)) + return; + failurePreservationCheckerCache.Add(actionPair); + + List<Variable> inputs = new List<Variable>(); + inputs.AddRange(first.thatInParams); + inputs.AddRange(second.thisInParams); + List<Variable> outputs = new List<Variable>(); + outputs.AddRange(first.thatOutParams); + outputs.AddRange(second.thisOutParams); + List<Variable> locals = new List<Variable>(); + locals.AddRange(second.thisAction.LocVars); + List<Block> secondBlocks = CloneBlocks(second.thisAction.Blocks); + HashSet<Variable> frame = new HashSet<Variable>(); + frame.UnionWith(first.gateUsedGlobalVars); + frame.UnionWith(second.gateUsedGlobalVars); + frame.UnionWith(second.actionUsedGlobalVars); + List<Requires> requires = DisjointnessRequires(program, first, second, frame); + Expr gateExpr = Expr.True; + foreach (AssertCmd assertCmd in first.thatGate) + { + gateExpr = Expr.And(gateExpr, assertCmd.Expr); + gateExpr.Type = Type.Bool; + } + gateExpr = Expr.Not(gateExpr); + gateExpr.Type = Type.Bool; + requires.Add(new Requires(false, gateExpr)); + List<Ensures> ensures = new List<Ensures>(); + Ensures ensureCheck = new Ensures(false, gateExpr); + ensureCheck.ErrorData = string.Format("Gate failure of {0} not preserved by {1}", first.proc.Name, second.proc.Name); + ensures.Add(ensureCheck); + foreach (AssertCmd assertCmd in second.thisGate) + requires.Add(new Requires(false, assertCmd.Expr)); + string checkerName = string.Format("FailurePreservationChecker_{0}_{1}", first.proc.Name, second.proc.Name); + List<IdentifierExpr> globalVars = new List<IdentifierExpr>(); + civlTypeChecker.SharedVariables.Iter(x => globalVars.Add(Expr.Ident(x))); + Procedure proc = new Procedure(Token.NoToken, checkerName, new List<TypeVariable>(), inputs, outputs, requires, globalVars, ensures); + Implementation impl = new Implementation(Token.NoToken, checkerName, new List<TypeVariable>(), inputs, outputs, locals, secondBlocks); + impl.Proc = proc; + this.decls.Add(impl); + this.decls.Add(proc); + } + + private void CreateNonBlockingChecker(Program program, AtomicActionInfo second) + { + List<Variable> inputs = new List<Variable>(); + inputs.AddRange(second.thisInParams); + + HashSet<Variable> frame = new HashSet<Variable>(); + frame.UnionWith(second.gateUsedGlobalVars); + frame.UnionWith(second.actionUsedGlobalVars); + List<Requires> requires = DisjointnessRequires(program, null, second, frame); + foreach (AssertCmd assertCmd in second.thisGate) + { + requires.Add(new Requires(false, assertCmd.Expr)); + } + HashSet<Variable> postExistVars = new HashSet<Variable>(); + postExistVars.UnionWith(frame); + postExistVars.UnionWith(second.thisOutParams); + Expr ensuresExpr = (new TransitionRelationComputation(program, second, frame, postExistVars)).TransitionRelationCompute(); + List<Ensures> ensures = new List<Ensures>(); + Ensures ensureCheck = new Ensures(false, ensuresExpr); + ensureCheck.ErrorData = string.Format("{0} is blocking", second.proc.Name); + ensures.Add(ensureCheck); + + List<Block> blocks = new List<Block>(); + blocks.Add(new Block(Token.NoToken, "L", new List<Cmd>(), new ReturnCmd(Token.NoToken))); + string checkerName = string.Format("NonBlockingChecker_{0}", second.proc.Name); + List<IdentifierExpr> globalVars = new List<IdentifierExpr>(); + civlTypeChecker.SharedVariables.Iter(x => globalVars.Add(Expr.Ident(x))); + Procedure proc = new Procedure(Token.NoToken, checkerName, new List<TypeVariable>(), inputs, new List<Variable>(), requires, globalVars, ensures); + Implementation impl = new Implementation(Token.NoToken, checkerName, new List<TypeVariable>(), inputs, new List<Variable>(), new List<Variable>(), blocks); + impl.Proc = proc; + this.decls.Add(impl); + this.decls.Add(proc); + } + } }
\ No newline at end of file diff --git a/Source/Concurrency/Program.cs b/Source/Concurrency/Program.cs index 8042476e..1be7cc07 100644 --- a/Source/Concurrency/Program.cs +++ b/Source/Concurrency/Program.cs @@ -1,44 +1,44 @@ -using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-
-namespace Microsoft.Boogie
-{
- public class Concurrency
- {
- public static void Transform(LinearTypeChecker linearTypeChecker, MoverTypeChecker moverTypeChecker)
- {
- List<Declaration> originalDecls = new List<Declaration>();
- Program program = linearTypeChecker.program;
- foreach (var decl in program.TopLevelDeclarations)
- {
- Procedure proc = decl as Procedure;
- if (proc != null && moverTypeChecker.procToActionInfo.ContainsKey(proc))
- {
- originalDecls.Add(proc);
- continue;
- }
- Implementation impl = decl as Implementation;
- if (impl != null && moverTypeChecker.procToActionInfo.ContainsKey(impl.Proc))
- {
- originalDecls.Add(impl);
- }
- }
-
- List<Declaration> decls = new List<Declaration>();
- if (!CommandLineOptions.Clo.TrustAtomicityTypes)
- {
- MoverCheck.AddCheckers(linearTypeChecker, moverTypeChecker, decls);
- }
- OwickiGries.AddCheckers(linearTypeChecker, moverTypeChecker, decls);
- foreach (Declaration decl in decls)
- {
- decl.Attributes = OwickiGries.RemoveYieldsAttribute(decl.Attributes);
- }
- program.RemoveTopLevelDeclarations(x => originalDecls.Contains(x));
- program.AddTopLevelDeclarations(decls);
- }
-
- }
-}
+using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Microsoft.Boogie +{ + public class Concurrency + { + public static void Transform(LinearTypeChecker linearTypeChecker, CivlTypeChecker civlTypeChecker) + { + List<Declaration> originalDecls = new List<Declaration>(); + Program program = linearTypeChecker.program; + foreach (var decl in program.TopLevelDeclarations) + { + Procedure proc = decl as Procedure; + if (proc != null && civlTypeChecker.procToActionInfo.ContainsKey(proc)) + { + originalDecls.Add(proc); + continue; + } + Implementation impl = decl as Implementation; + if (impl != null && civlTypeChecker.procToActionInfo.ContainsKey(impl.Proc)) + { + originalDecls.Add(impl); + } + } + + List<Declaration> decls = new List<Declaration>(); + if (!CommandLineOptions.Clo.TrustAtomicityTypes) + { + MoverCheck.AddCheckers(linearTypeChecker, civlTypeChecker, decls); + } + CivlRefinement.AddCheckers(linearTypeChecker, civlTypeChecker, decls); + foreach (Declaration decl in decls) + { + decl.Attributes = CivlRefinement.RemoveYieldsAttribute(decl.Attributes); + } + program.RemoveTopLevelDeclarations(x => originalDecls.Contains(x)); + program.AddTopLevelDeclarations(decls); + } + + } +} diff --git a/Source/Concurrency/Properties/AssemblyInfo.cs b/Source/Concurrency/Properties/AssemblyInfo.cs index 48430488..7e90c12f 100644 --- a/Source/Concurrency/Properties/AssemblyInfo.cs +++ b/Source/Concurrency/Properties/AssemblyInfo.cs @@ -1,36 +1,36 @@ -using System.Reflection;
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
-
-// General Information about an assembly is controlled through the following
-// set of attributes. Change these attribute values to modify the information
-// associated with an assembly.
-[assembly: AssemblyTitle("Concurrency")]
-[assembly: AssemblyDescription("")]
-[assembly: AssemblyConfiguration("")]
-[assembly: AssemblyCompany("")]
-[assembly: AssemblyProduct("Concurrency")]
-[assembly: AssemblyCopyright("Copyright © 2013")]
-[assembly: AssemblyTrademark("")]
-[assembly: AssemblyCulture("")]
-
-// Setting ComVisible to false makes the types in this assembly not visible
-// to COM components. If you need to access a type in this assembly from
-// COM, set the ComVisible attribute to true on that type.
-[assembly: ComVisible(false)]
-
-// The following GUID is for the ID of the typelib if this project is exposed to COM
-[assembly: Guid("867039c5-87dc-4f76-9f90-4f52afc90116")]
-
-// Version information for an assembly consists of the following four values:
-//
-// Major Version
-// Minor Version
-// Build Number
-// Revision
-//
-// You can specify all the values or you can default the Build and Revision Numbers
-// by using the '*' as shown below:
-// [assembly: AssemblyVersion("1.0.*")]
-[assembly: AssemblyVersion("1.0.0.0")]
-[assembly: AssemblyFileVersion("1.0.0.0")]
+using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Concurrency")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Concurrency")] +[assembly: AssemblyCopyright("Copyright © 2013")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("867039c5-87dc-4f76-9f90-4f52afc90116")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Source/Concurrency/SimulationRelation.cs b/Source/Concurrency/SimulationRelation.cs index 7f130f76..c97ebfb7 100644 --- a/Source/Concurrency/SimulationRelation.cs +++ b/Source/Concurrency/SimulationRelation.cs @@ -1,197 +1,197 @@ -using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using Microsoft.Boogie.GraphUtil;
-
-namespace Microsoft.Boogie
-{
- public class SimulationRelation<A, B, L>
- {
- class Graph<T>
- {
- HashSet<T> nodes;
- Dictionary<T, Dictionary<L, List<T>>> successors;
- Dictionary<T, Dictionary<L, List<T>>> predecessors;
-
- public Graph(List<Tuple<T, L, T>> edges)
- {
- nodes = new HashSet<T>();
- successors = new Dictionary<T, Dictionary<L, List<T>>>();
- predecessors = new Dictionary<T, Dictionary<L, List<T>>>();
- foreach (Tuple<T, L, T> edge in edges)
- {
- T source = edge.Item1;
- L label = edge.Item2;
- T dest = edge.Item3;
- nodes.Add(source);
- nodes.Add(dest);
- if (!successors.ContainsKey(source))
- {
- successors[source] = new Dictionary<L, List<T>>();
- }
- if (!successors[source].ContainsKey(label))
- {
- successors[source][label] = new List<T>();
- }
- if (!predecessors.ContainsKey(dest))
- {
- predecessors[dest] = new Dictionary<L, List<T>>();
- }
- if (!predecessors[dest].ContainsKey(label))
- {
- predecessors[dest][label] = new List<T>();
- }
- successors[source][label].Add(dest);
- predecessors[dest][label].Add(source);
- }
- }
-
- public IEnumerable<T> Nodes { get { return nodes; } }
-
- public IEnumerable<T> Post(T t, L l)
- {
- if (successors.ContainsKey(t) && successors[t].ContainsKey(l))
- {
- return successors[t][l];
- }
- else
- {
- return Enumerable.Empty<T>();
- }
- }
-
- public IEnumerable<T> Post(IEnumerable<T> set, L l)
- {
- return set.Select(x => Post(x, l)).Aggregate(Enumerable.Empty<T>(), (p, q) => p.Concat(q));
- }
-
- public IEnumerable<T> Pre(T t, L l)
- {
- if (predecessors.ContainsKey(t) && predecessors[t].ContainsKey(l))
- {
- return predecessors[t][l];
- }
- else
- {
- return Enumerable.Empty<T>();
- }
- }
-
- public IEnumerable<T> Pre(IEnumerable<T> set, L l)
- {
- return set.Select(x => Pre(x, l)).Aggregate(Enumerable.Empty<T>(), (p, q) => p.Concat(q));
- }
-
- public IEnumerable<L> PostLabels(T t)
- {
- if (successors.ContainsKey(t))
- {
- return successors[t].Keys;
- }
- else
- {
- return Enumerable.Empty<L>();
- }
- }
-
- public IEnumerable<L> PreLabels(T t)
- {
- if (predecessors.ContainsKey(t))
- {
- return predecessors[t].Keys;
- }
- else
- {
- return Enumerable.Empty<L>();
- }
- }
- }
-
- Graph<A> aGraph;
- Graph<B> bGraph;
- Dictionary<A, HashSet<B>> initialConstraints;
-
- public SimulationRelation(List<Tuple<A, L, A>> aEdges, List<Tuple<B, L, B>> bEdges, Dictionary<A, HashSet<B>> initialConstraints)
- {
- this.aGraph = new Graph<A>(aEdges);
- this.bGraph = new Graph<B>(bEdges);
- this.initialConstraints = initialConstraints;
- }
-
- public Dictionary<A, HashSet<B>> ComputeSimulationRelation()
- {
- Dictionary<A, HashSet<B>> prevsim;
- Dictionary<A, HashSet<B>> sim;
- Dictionary<Tuple<A, L>, HashSet<B>> remove;
- Queue<Tuple<A,L>> workQueue;
-
- prevsim = new Dictionary<A, HashSet<B>>();
- sim = new Dictionary<A, HashSet<B>>();
- remove = new Dictionary<Tuple<A, L>, HashSet<B>>();
- workQueue = new Queue<Tuple<A,L>>();
- foreach (var a in aGraph.Nodes)
- {
- prevsim[a] = new HashSet<B>(bGraph.Nodes);
- sim[a] = new HashSet<B>();
- HashSet<L> aOutgoingLabels = new HashSet<L>(aGraph.PostLabels(a));
- foreach (var b in bGraph.Nodes)
- {
- IEnumerable<L> bOutgoingLabels = bGraph.PostLabels(b);
- if (aOutgoingLabels.IsSubsetOf(bOutgoingLabels))
- {
- sim[a].Add(b);
- }
- }
- if (initialConstraints.ContainsKey(a))
- {
- sim[a].IntersectWith(initialConstraints[a]);
- }
-
- foreach (var l in aGraph.PreLabels(a))
- {
- Tuple<A, L> x = new Tuple<A, L>(a, l);
- remove[x] = new HashSet<B>(bGraph.Pre(prevsim[a], l).Except(bGraph.Pre(sim[a], l)));
- if (remove[x].Count > 0)
- {
- workQueue.Enqueue(x);
- }
- }
- }
-
- while (workQueue.Count > 0)
- {
- Tuple<A,L> x = workQueue.Dequeue();
- A v = x.Item1;
- foreach (A u in aGraph.Pre(v, x.Item2))
- {
- foreach (B w in remove[x])
- {
- if (sim[u].Contains(w))
- {
- sim[u].Remove(w);
- foreach (L l in bGraph.PreLabels(w))
- {
- foreach (B b in bGraph.Pre(w, l))
- {
- if (bGraph.Post(b, l).Intersect(sim[u]).Count() == 0)
- {
- Tuple<A, L> z = new Tuple<A, L>(u, l);
- if (!remove.ContainsKey(z))
- remove[z] = new HashSet<B>();
- remove[z].Add(b);
- workQueue.Enqueue(z);
- }
- }
- }
- }
- }
- }
- prevsim[v] = new HashSet<B>(sim[v]);
- remove[x] = new HashSet<B>();
- }
-
- return sim;
- }
- }
-}
+using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Microsoft.Boogie.GraphUtil; + +namespace Microsoft.Boogie +{ + public class SimulationRelation<A, B, L> + { + class Graph<T> + { + HashSet<T> nodes; + Dictionary<T, Dictionary<L, List<T>>> successors; + Dictionary<T, Dictionary<L, List<T>>> predecessors; + + public Graph(List<Tuple<T, L, T>> edges) + { + nodes = new HashSet<T>(); + successors = new Dictionary<T, Dictionary<L, List<T>>>(); + predecessors = new Dictionary<T, Dictionary<L, List<T>>>(); + foreach (Tuple<T, L, T> edge in edges) + { + T source = edge.Item1; + L label = edge.Item2; + T dest = edge.Item3; + nodes.Add(source); + nodes.Add(dest); + if (!successors.ContainsKey(source)) + { + successors[source] = new Dictionary<L, List<T>>(); + } + if (!successors[source].ContainsKey(label)) + { + successors[source][label] = new List<T>(); + } + if (!predecessors.ContainsKey(dest)) + { + predecessors[dest] = new Dictionary<L, List<T>>(); + } + if (!predecessors[dest].ContainsKey(label)) + { + predecessors[dest][label] = new List<T>(); + } + successors[source][label].Add(dest); + predecessors[dest][label].Add(source); + } + } + + public IEnumerable<T> Nodes { get { return nodes; } } + + public IEnumerable<T> Post(T t, L l) + { + if (successors.ContainsKey(t) && successors[t].ContainsKey(l)) + { + return successors[t][l]; + } + else + { + return Enumerable.Empty<T>(); + } + } + + public IEnumerable<T> Post(IEnumerable<T> set, L l) + { + return set.Select(x => Post(x, l)).Aggregate(Enumerable.Empty<T>(), (p, q) => p.Concat(q)); + } + + public IEnumerable<T> Pre(T t, L l) + { + if (predecessors.ContainsKey(t) && predecessors[t].ContainsKey(l)) + { + return predecessors[t][l]; + } + else + { + return Enumerable.Empty<T>(); + } + } + + public IEnumerable<T> Pre(IEnumerable<T> set, L l) + { + return set.Select(x => Pre(x, l)).Aggregate(Enumerable.Empty<T>(), (p, q) => p.Concat(q)); + } + + public IEnumerable<L> PostLabels(T t) + { + if (successors.ContainsKey(t)) + { + return successors[t].Keys; + } + else + { + return Enumerable.Empty<L>(); + } + } + + public IEnumerable<L> PreLabels(T t) + { + if (predecessors.ContainsKey(t)) + { + return predecessors[t].Keys; + } + else + { + return Enumerable.Empty<L>(); + } + } + } + + Graph<A> aGraph; + Graph<B> bGraph; + Dictionary<A, HashSet<B>> initialConstraints; + + public SimulationRelation(List<Tuple<A, L, A>> aEdges, List<Tuple<B, L, B>> bEdges, Dictionary<A, HashSet<B>> initialConstraints) + { + this.aGraph = new Graph<A>(aEdges); + this.bGraph = new Graph<B>(bEdges); + this.initialConstraints = initialConstraints; + } + + public Dictionary<A, HashSet<B>> ComputeSimulationRelation() + { + Dictionary<A, HashSet<B>> prevsim; + Dictionary<A, HashSet<B>> sim; + Dictionary<Tuple<A, L>, HashSet<B>> remove; + Queue<Tuple<A,L>> workQueue; + + prevsim = new Dictionary<A, HashSet<B>>(); + sim = new Dictionary<A, HashSet<B>>(); + remove = new Dictionary<Tuple<A, L>, HashSet<B>>(); + workQueue = new Queue<Tuple<A,L>>(); + foreach (var a in aGraph.Nodes) + { + prevsim[a] = new HashSet<B>(bGraph.Nodes); + sim[a] = new HashSet<B>(); + HashSet<L> aOutgoingLabels = new HashSet<L>(aGraph.PostLabels(a)); + foreach (var b in bGraph.Nodes) + { + IEnumerable<L> bOutgoingLabels = bGraph.PostLabels(b); + if (aOutgoingLabels.IsSubsetOf(bOutgoingLabels)) + { + sim[a].Add(b); + } + } + if (initialConstraints.ContainsKey(a)) + { + sim[a].IntersectWith(initialConstraints[a]); + } + + foreach (var l in aGraph.PreLabels(a)) + { + Tuple<A, L> x = new Tuple<A, L>(a, l); + remove[x] = new HashSet<B>(bGraph.Pre(prevsim[a], l).Except(bGraph.Pre(sim[a], l))); + if (remove[x].Count > 0) + { + workQueue.Enqueue(x); + } + } + } + + while (workQueue.Count > 0) + { + Tuple<A,L> x = workQueue.Dequeue(); + A v = x.Item1; + foreach (A u in aGraph.Pre(v, x.Item2)) + { + foreach (B w in remove[x]) + { + if (sim[u].Contains(w)) + { + sim[u].Remove(w); + foreach (L l in bGraph.PreLabels(w)) + { + foreach (B b in bGraph.Pre(w, l)) + { + if (bGraph.Post(b, l).Intersect(sim[u]).Count() == 0) + { + Tuple<A, L> z = new Tuple<A, L>(u, l); + if (!remove.ContainsKey(z)) + remove[z] = new HashSet<B>(); + remove[z].Add(b); + workQueue.Enqueue(z); + } + } + } + } + } + } + prevsim[v] = new HashSet<B>(sim[v]); + remove[x] = new HashSet<B>(); + } + + return sim; + } + } +} diff --git a/Source/Concurrency/TypeCheck.cs b/Source/Concurrency/TypeCheck.cs deleted file mode 100644 index f2b2c0ca..00000000 --- a/Source/Concurrency/TypeCheck.cs +++ /dev/null @@ -1,724 +0,0 @@ -using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using Microsoft.Boogie;
-using System.Diagnostics.Contracts;
-using System.Diagnostics;
-
-namespace Microsoft.Boogie
-{
- public enum MoverType
- {
- Top,
- Atomic,
- Right,
- Left,
- Both
- }
-
- public class ActionInfo
- {
- public Procedure proc;
- public int createdAtLayerNum;
- public int availableUptoLayerNum;
- public bool hasImplementation;
-
- public ActionInfo(Procedure proc, int createdAtLayerNum, int availableUptoLayerNum)
- {
- this.proc = proc;
- this.createdAtLayerNum = createdAtLayerNum;
- this.availableUptoLayerNum = availableUptoLayerNum;
- this.hasImplementation = false;
- }
-
- public virtual bool IsRightMover
- {
- get { return true; }
- }
-
- public virtual bool IsLeftMover
- {
- get { return true; }
- }
- }
-
- public class AtomicActionInfo : ActionInfo
- {
- public Ensures ensures;
- public MoverType moverType;
- public List<AssertCmd> thisGate;
- public CodeExpr thisAction;
- public List<Variable> thisInParams;
- public List<Variable> thisOutParams;
- public List<AssertCmd> thatGate;
- public CodeExpr thatAction;
- public List<Variable> thatInParams;
- public List<Variable> thatOutParams;
- public HashSet<Variable> actionUsedGlobalVars;
- public HashSet<Variable> modifiedGlobalVars;
- public HashSet<Variable> gateUsedGlobalVars;
- public bool hasAssumeCmd;
-
- public bool CommutesWith(AtomicActionInfo actionInfo)
- {
- if (this.modifiedGlobalVars.Intersect(actionInfo.actionUsedGlobalVars).Count() > 0)
- return false;
- if (this.actionUsedGlobalVars.Intersect(actionInfo.modifiedGlobalVars).Count() > 0)
- return false;
- return true;
- }
-
- public override bool IsRightMover
- {
- get { return moverType == MoverType.Right || moverType == MoverType.Both; }
- }
-
- public override bool IsLeftMover
- {
- get { return moverType == MoverType.Left || moverType == MoverType.Both; }
- }
-
- public AtomicActionInfo(Procedure proc, Ensures ensures, MoverType moverType, int layerNum, int availableUptoLayerNum)
- : base(proc, layerNum, availableUptoLayerNum)
- {
- CodeExpr codeExpr = ensures.Condition as CodeExpr;
- this.ensures = ensures;
- this.moverType = moverType;
- this.thisGate = new List<AssertCmd>();
- this.thisAction = codeExpr;
- this.thisInParams = new List<Variable>();
- this.thisOutParams = new List<Variable>();
- this.thatGate = new List<AssertCmd>();
- this.thatInParams = new List<Variable>();
- this.thatOutParams = new List<Variable>();
- this.hasAssumeCmd = false;
-
- foreach (Block block in codeExpr.Blocks)
- {
- block.Cmds.ForEach(x => this.hasAssumeCmd = this.hasAssumeCmd || x is AssumeCmd);
- }
-
- var cmds = thisAction.Blocks[0].Cmds;
- for (int i = 0; i < cmds.Count; i++)
- {
- AssertCmd assertCmd = cmds[i] as AssertCmd;
- if (assertCmd == null) break;
- thisGate.Add(assertCmd);
- cmds[i] = new AssumeCmd(assertCmd.tok, Expr.True);
- }
-
- Dictionary<Variable, Expr> map = new Dictionary<Variable, Expr>();
- foreach (Variable x in proc.InParams)
- {
- this.thisInParams.Add(x);
- Variable y = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "that_" + x.Name, x.TypedIdent.Type), true, x.Attributes);
- this.thatInParams.Add(y);
- map[x] = Expr.Ident(y);
- }
- foreach (Variable x in proc.OutParams)
- {
- this.thisOutParams.Add(x);
- Variable y = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "that_" + x.Name, x.TypedIdent.Type), false, x.Attributes);
- this.thatOutParams.Add(y);
- map[x] = Expr.Ident(y);
- }
- List<Variable> thatLocVars = new List<Variable>();
- foreach (Variable x in thisAction.LocVars)
- {
- Variable y = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "that_" + x.Name, x.TypedIdent.Type), false);
- map[x] = Expr.Ident(y);
- thatLocVars.Add(y);
- }
- Contract.Assume(proc.TypeParameters.Count == 0);
- Substitution subst = Substituter.SubstitutionFromHashtable(map);
- foreach (AssertCmd assertCmd in thisGate)
- {
- thatGate.Add((AssertCmd)Substituter.Apply(subst, assertCmd));
- }
- Dictionary<Block, Block> blockMap = new Dictionary<Block, Block>();
- List<Block> thatBlocks = new List<Block>();
- foreach (Block block in thisAction.Blocks)
- {
- List<Cmd> otherCmds = new List<Cmd>();
- foreach (Cmd cmd in block.Cmds)
- {
- otherCmds.Add(Substituter.Apply(subst, cmd));
- }
- Block thatBlock = new Block();
- thatBlock.Cmds = otherCmds;
- thatBlock.Label = "that_" + block.Label;
- block.Label = "this_" + block.Label;
- thatBlocks.Add(thatBlock);
- blockMap[block] = thatBlock;
- if (block.TransferCmd is GotoCmd)
- {
- GotoCmd gotoCmd = block.TransferCmd as GotoCmd;
- for (int i = 0; i < gotoCmd.labelNames.Count; i++)
- {
- gotoCmd.labelNames[i] = "this_" + gotoCmd.labelNames[i];
- }
- }
- }
- foreach (Block block in thisAction.Blocks)
- {
- if (block.TransferCmd is ReturnExprCmd)
- {
- block.TransferCmd = new ReturnCmd(block.TransferCmd.tok);
- blockMap[block].TransferCmd = new ReturnCmd(block.TransferCmd.tok);
- continue;
- }
- List<Block> thatGotoCmdLabelTargets = new List<Block>();
- List<string> thatGotoCmdLabelNames = new List<string>();
- GotoCmd gotoCmd = block.TransferCmd as GotoCmd;
- foreach (Block target in gotoCmd.labelTargets)
- {
- thatGotoCmdLabelTargets.Add(blockMap[target]);
- thatGotoCmdLabelNames.Add(blockMap[target].Label);
- }
- blockMap[block].TransferCmd = new GotoCmd(block.TransferCmd.tok, thatGotoCmdLabelNames, thatGotoCmdLabelTargets);
- }
- this.thatAction = new CodeExpr(thatLocVars, thatBlocks);
-
- {
- VariableCollector collector = new VariableCollector();
- collector.Visit(codeExpr);
- this.actionUsedGlobalVars = new HashSet<Variable>(collector.usedVars.Where(x => x is GlobalVariable));
- }
-
- List<Variable> modifiedVars = new List<Variable>();
- foreach (Block block in codeExpr.Blocks)
- {
- block.Cmds.ForEach(cmd => cmd.AddAssignedVariables(modifiedVars));
- }
- this.modifiedGlobalVars = new HashSet<Variable>(modifiedVars.Where(x => x is GlobalVariable));
-
- {
- VariableCollector collector = new VariableCollector();
- this.thisGate.ForEach(assertCmd => collector.Visit(assertCmd));
- this.gateUsedGlobalVars = new HashSet<Variable>(collector.usedVars.Where(x => x is GlobalVariable));
- }
- }
- }
-
- public class SharedVariableInfo
- {
- public int introLayerNum;
- public int hideLayerNum;
-
- public SharedVariableInfo(int introLayerNum, int hideLayerNum)
- {
- this.introLayerNum = introLayerNum;
- this.hideLayerNum = hideLayerNum;
- }
- }
-
- public class LayerEraser : ReadOnlyVisitor
- {
- private QKeyValue RemoveLayerAttribute(QKeyValue iter)
- {
- if (iter == null) return null;
- iter.Next = RemoveLayerAttribute(iter.Next);
- return (iter.Key == "layer") ? iter.Next : iter;
- }
-
- public override Variable VisitVariable(Variable node)
- {
- node.Attributes = RemoveLayerAttribute(node.Attributes);
- return base.VisitVariable(node);
- }
-
- public override Procedure VisitProcedure(Procedure node)
- {
- node.Attributes = RemoveLayerAttribute(node.Attributes);
- return base.VisitProcedure(node);
- }
-
- public override Implementation VisitImplementation(Implementation node)
- {
- node.Attributes = RemoveLayerAttribute(node.Attributes);
- return base.VisitImplementation(node);
- }
-
- public override Requires VisitRequires(Requires node)
- {
- node.Attributes = RemoveLayerAttribute(node.Attributes);
- return base.VisitRequires(node);
- }
-
- public override Ensures VisitEnsures(Ensures node)
- {
- node.Attributes = RemoveLayerAttribute(node.Attributes);
- return base.VisitEnsures(node);
- }
-
- public override Cmd VisitAssertCmd(AssertCmd node)
- {
- node.Attributes = RemoveLayerAttribute(node.Attributes);
- return base.VisitAssertCmd(node);
- }
- }
-
- public class MoverTypeChecker : ReadOnlyVisitor
- {
- CheckingContext checkingContext;
- public int errorCount;
- public Dictionary<Variable, SharedVariableInfo> globalVarToSharedVarInfo;
- Procedure enclosingProc;
- Implementation enclosingImpl;
- public Dictionary<Procedure, ActionInfo> procToActionInfo;
- public Program program;
- bool canAccessSharedVars;
- bool canAccessAuxVars;
- int minLayerNum;
- int maxLayerNum;
- public Dictionary<Absy, HashSet<int>> absyToLayerNums;
- HashSet<Variable> auxVars;
- public int leastUnimplementedLayerNum;
-
- private static List<int> FindLayers(QKeyValue kv)
- {
- HashSet<int> attrs = new HashSet<int>();
- for (; kv != null; kv = kv.Next)
- {
- if (kv.Key != "layer") continue;
- foreach (var o in kv.Params)
- {
- Expr e = o as Expr;
- if (e == null) continue;
- LiteralExpr l = e as LiteralExpr;
- if (l != null && l.isBigNum)
- attrs.Add(l.asBigNum.ToIntSafe);
- }
- }
- List<int> layers = attrs.ToList();
- layers.Sort();
- return layers;
- }
-
- private static MoverType GetMoverType(Ensures e)
- {
- if (QKeyValue.FindBoolAttribute(e.Attributes, "atomic"))
- return MoverType.Atomic;
- if (QKeyValue.FindBoolAttribute(e.Attributes, "right"))
- return MoverType.Right;
- if (QKeyValue.FindBoolAttribute(e.Attributes, "left"))
- return MoverType.Left;
- if (QKeyValue.FindBoolAttribute(e.Attributes, "both"))
- return MoverType.Both;
- return MoverType.Top;
- }
-
- public MoverTypeChecker(Program program)
- {
- this.auxVars = new HashSet<Variable>();
- this.absyToLayerNums = new Dictionary<Absy, HashSet<int>>();
- this.globalVarToSharedVarInfo = new Dictionary<Variable, SharedVariableInfo>();
- this.procToActionInfo = new Dictionary<Procedure, ActionInfo>();
- this.errorCount = 0;
- this.checkingContext = new CheckingContext(null);
- this.program = program;
- this.enclosingProc = null;
- this.enclosingImpl = null;
- this.canAccessSharedVars = false;
- this.canAccessAuxVars = false;
- this.minLayerNum = int.MaxValue;
- this.maxLayerNum = -1;
- this.leastUnimplementedLayerNum = int.MaxValue;
- foreach (var g in program.GlobalVariables)
- {
- List<int> layerNums = FindLayers(g.Attributes);
- if (layerNums.Count == 0)
- {
- // Cannot access atomic actions
- }
- else if (layerNums.Count == 1)
- {
- this.globalVarToSharedVarInfo[g] = new SharedVariableInfo(layerNums[0], int.MaxValue);
- }
- else if (layerNums.Count == 2)
- {
- this.globalVarToSharedVarInfo[g] = new SharedVariableInfo(layerNums[0], layerNums[1]);
- }
- else
- {
- Error(g, "Too many layer numbers");
- }
- }
- }
-
- private HashSet<int> allCreatedLayerNums;
- public IEnumerable<int> AllCreatedLayerNums
- {
- get
- {
- if (allCreatedLayerNums == null)
- {
- allCreatedLayerNums = new HashSet<int>();
- foreach (ActionInfo actionInfo in procToActionInfo.Values)
- {
- allCreatedLayerNums.Add(actionInfo.createdAtLayerNum);
- }
- }
- return allCreatedLayerNums;
- }
- }
-
- public void TypeCheck()
- {
- foreach (var proc in program.Procedures)
- {
- if (!QKeyValue.FindBoolAttribute(proc.Attributes, "yields")) continue;
-
- int createdAtLayerNum; // must be initialized by the following code, otherwise it is an error
- int availableUptoLayerNum = int.MaxValue;
- List<int> attrs = FindLayers(proc.Attributes);
- if (attrs.Count == 1)
- {
- createdAtLayerNum = attrs[0];
- }
- else if (attrs.Count == 2)
- {
- createdAtLayerNum = attrs[0];
- availableUptoLayerNum = attrs[1];
- }
- else
- {
- Error(proc, "Incorrect number of layers");
- continue;
- }
- if (availableUptoLayerNum <= createdAtLayerNum)
- {
- Error(proc, "Creation layer number must be less than the available upto layer number");
- continue;
- }
- foreach (Ensures e in proc.Ensures)
- {
- MoverType moverType = GetMoverType(e);
- if (moverType == MoverType.Top) continue;
- CodeExpr codeExpr = e.Condition as CodeExpr;
- if (codeExpr == null)
- {
- Error(e, "An atomic action must be a CodeExpr");
- continue;
- }
- if (procToActionInfo.ContainsKey(proc))
- {
- Error(proc, "A procedure can have at most one atomic action");
- continue;
- }
-
- minLayerNum = int.MaxValue;
- maxLayerNum = -1;
- canAccessSharedVars = true;
- enclosingProc = proc;
- enclosingImpl = null;
- base.VisitEnsures(e);
- canAccessSharedVars = false;
- if (maxLayerNum > createdAtLayerNum)
- {
- Error(e, "A variable being accessed is introduced after this action is created");
- }
- else if (availableUptoLayerNum > minLayerNum)
- {
- Error(e, "A variable being accessed is hidden before this action becomes unavailable");
- }
- else
- {
- procToActionInfo[proc] = new AtomicActionInfo(proc, e, moverType, createdAtLayerNum, availableUptoLayerNum);
- }
- }
- if (errorCount > 0) continue;
- if (!procToActionInfo.ContainsKey(proc))
- {
- procToActionInfo[proc] = new ActionInfo(proc, createdAtLayerNum, availableUptoLayerNum);
- }
- }
- if (errorCount > 0) return;
- foreach (var impl in program.Implementations)
- {
- if (!procToActionInfo.ContainsKey(impl.Proc)) continue;
- procToActionInfo[impl.Proc].hasImplementation = true;
- }
- foreach (var proc in procToActionInfo.Keys)
- {
- ActionInfo actionInfo = procToActionInfo[proc];
- if (actionInfo.hasImplementation) continue;
- if (leastUnimplementedLayerNum == int.MaxValue)
- {
- leastUnimplementedLayerNum = actionInfo.createdAtLayerNum;
- }
- else if (leastUnimplementedLayerNum == actionInfo.createdAtLayerNum)
- {
- // do nothing
- }
- else
- {
- Error(proc, "All unimplemented atomic actions must be created at the same layer");
- }
- }
- foreach (var g in this.globalVarToSharedVarInfo.Keys)
- {
- var info = globalVarToSharedVarInfo[g];
- if (!this.AllCreatedLayerNums.Contains(info.introLayerNum))
- {
- Error(g, "Variable must be introduced with creation of some atomic action");
- }
- if (info.hideLayerNum != int.MaxValue && !this.AllCreatedLayerNums.Contains(info.hideLayerNum))
- {
- Error(g, "Variable must be hidden with creation of some atomic action");
- }
- }
- if (errorCount > 0) return;
- this.VisitProgram(program);
- if (errorCount > 0) return;
- YieldTypeChecker.PerformYieldSafeCheck(this);
- new LayerEraser().VisitProgram(program);
- }
-
- public IEnumerable<Variable> SharedVariables
- {
- get { return this.globalVarToSharedVarInfo.Keys; }
- }
-
- public override Implementation VisitImplementation(Implementation node)
- {
- if (!procToActionInfo.ContainsKey(node.Proc))
- {
- return node;
- }
- this.enclosingImpl = node;
- this.enclosingProc = null;
- auxVars = new HashSet<Variable>();
- foreach (Variable v in node.LocVars)
- {
- if (QKeyValue.FindBoolAttribute(v.Attributes, "aux"))
- {
- auxVars.Add(v);
- }
- }
- return base.VisitImplementation(node);
- }
-
- public override Procedure VisitProcedure(Procedure node)
- {
- if (!procToActionInfo.ContainsKey(node))
- {
- return node;
- }
- this.enclosingProc = node;
- this.enclosingImpl = null;
- return base.VisitProcedure(node);
- }
-
- public override Cmd VisitCallCmd(CallCmd node)
- {
- int enclosingProcLayerNum = procToActionInfo[enclosingImpl.Proc].createdAtLayerNum;
- if (procToActionInfo.ContainsKey(node.Proc))
- {
- ActionInfo actionInfo = procToActionInfo[node.Proc];
- if (node.IsAsync && actionInfo is AtomicActionInfo)
- {
- Error(node, "Target of async call cannot be an atomic action");
- }
- int calleeLayerNum = procToActionInfo[node.Proc].createdAtLayerNum;
- if (enclosingProcLayerNum < calleeLayerNum ||
- (enclosingProcLayerNum == calleeLayerNum && actionInfo is AtomicActionInfo))
- {
- Error(node, "The layer of the caller must be greater than the layer of the callee");
- }
- else if (enclosingProcLayerNum == calleeLayerNum && enclosingImpl.OutParams.Count > 0)
- {
- HashSet<Variable> outParams = new HashSet<Variable>(enclosingImpl.OutParams);
- foreach (var x in node.Outs)
- {
- if (x.Decl is GlobalVariable)
- {
- Error(node, "A global variable cannot be used as output argument for this call");
- }
- else if (outParams.Contains(x.Decl))
- {
- Error(node, "An output variable of the enclosing implementation cannot be used as output argument for this call");
- }
- }
- }
- if (actionInfo.availableUptoLayerNum < enclosingProcLayerNum)
- {
- Error(node, "The callee is not available in the caller procedure");
- }
- }
- else
- {
- Error(node, "Yielding procedure can call only a yielding procedure");
- }
- return base.VisitCallCmd(node);
- }
-
- public override Cmd VisitParCallCmd(ParCallCmd node)
- {
- int enclosingProcLayerNum = procToActionInfo[enclosingImpl.Proc].createdAtLayerNum;
- bool isLeftMover = true;
- bool isRightMover = true;
- int maxCalleeLayerNum = 0;
- int numAtomicActions = 0;
- foreach (CallCmd iter in node.CallCmds)
- {
- ActionInfo actionInfo = procToActionInfo[iter.Proc];
- isLeftMover = isLeftMover && actionInfo.IsLeftMover;
- isRightMover = isRightMover && actionInfo.IsRightMover;
- if (actionInfo.createdAtLayerNum > maxCalleeLayerNum)
- {
- maxCalleeLayerNum = actionInfo.createdAtLayerNum;
- }
- if (actionInfo is AtomicActionInfo)
- {
- numAtomicActions++;
- }
- }
- if (maxCalleeLayerNum < enclosingProcLayerNum && !isLeftMover && !isRightMover && node.CallCmds.Count > 1)
- {
- Error(node, "The callees in the parallel call must be all right movers or all left movers");
- }
- if (maxCalleeLayerNum == enclosingProcLayerNum && numAtomicActions > 0)
- {
- Error(node, "If some callee in the parallel call has the same layer as the enclosing procedure, then no callee can be an atomic action");
- }
- return base.VisitParCallCmd(node);
- }
-
- public override Cmd VisitAssignCmd(AssignCmd node)
- {
- Contract.Ensures(Contract.Result<Cmd>() == node);
- for (int i = 0; i < node.Lhss.Count; ++i)
- {
- bool savedCanAccessSharedVars = canAccessSharedVars;
- bool savedCanAccessAuxVars = canAccessAuxVars;
- Variable v = node.Lhss[i].DeepAssignedVariable;
- if (v is LocalVariable && auxVars.Contains(v))
- {
- canAccessSharedVars = true;
- canAccessAuxVars = true;
- }
- this.Visit(node.Lhss[i]);
- this.Visit(node.Rhss[i]);
- canAccessSharedVars = savedCanAccessSharedVars;
- canAccessAuxVars = savedCanAccessAuxVars;
- }
- return node;
- }
-
- public override Expr VisitIdentifierExpr(IdentifierExpr node)
- {
- if (node.Decl is GlobalVariable)
- {
- if (!canAccessSharedVars)
- {
- Error(node, "Shared variable can be accessed only in atomic actions or specifications");
- }
- else if (this.globalVarToSharedVarInfo.ContainsKey(node.Decl))
- {
- if (this.globalVarToSharedVarInfo[node.Decl].hideLayerNum < minLayerNum)
- {
- minLayerNum = this.globalVarToSharedVarInfo[node.Decl].hideLayerNum;
- }
- if (this.globalVarToSharedVarInfo[node.Decl].introLayerNum > maxLayerNum)
- {
- maxLayerNum = this.globalVarToSharedVarInfo[node.Decl].introLayerNum;
- }
- }
- else
- {
- Error(node, "Accessed shared variable must have layer annotation");
- }
- }
- else if (node.Decl is LocalVariable && auxVars.Contains(node.Decl) && !canAccessAuxVars)
- {
- Error(node, "Auxiliary variable can be accessed only in assertions");
- }
-
- return base.VisitIdentifierExpr(node);
- }
-
- public override Ensures VisitEnsures(Ensures ensures)
- {
- minLayerNum = int.MaxValue;
- maxLayerNum = -1;
- canAccessSharedVars = true;
- Ensures ret = base.VisitEnsures(ensures);
- canAccessSharedVars = false;
- ActionInfo actionInfo = procToActionInfo[enclosingProc];
- AtomicActionInfo atomicActionInfo = actionInfo as AtomicActionInfo;
- if (atomicActionInfo != null && atomicActionInfo.ensures == ensures)
- {
- // This case has already been checked
- }
- else
- {
- CheckAndAddLayers(ensures, ensures.Attributes, actionInfo.createdAtLayerNum);
- }
- return ret;
- }
-
- public override Requires VisitRequires(Requires requires)
- {
- minLayerNum = int.MaxValue;
- maxLayerNum = -1;
- canAccessSharedVars = true;
- Requires ret = base.VisitRequires(requires);
- canAccessSharedVars = false;
- CheckAndAddLayers(requires, requires.Attributes, procToActionInfo[enclosingProc].createdAtLayerNum);
- return ret;
- }
-
- public override Cmd VisitAssertCmd(AssertCmd node)
- {
- if (enclosingImpl == null)
- return base.VisitAssertCmd(node);
- minLayerNum = int.MaxValue;
- maxLayerNum = -1;
- canAccessSharedVars = true;
- canAccessAuxVars = true;
- Cmd ret = base.VisitAssertCmd(node);
- canAccessAuxVars = false;
- canAccessSharedVars = false;
- CheckAndAddLayers(node, node.Attributes, procToActionInfo[enclosingImpl.Proc].createdAtLayerNum);
- return ret;
- }
-
- private void CheckAndAddLayers(Absy node, QKeyValue attributes, int enclosingProcLayerNum)
- {
- List<int> attrs = FindLayers(attributes);
- if (attrs.Count == 0)
- {
- Error(node, "layer not present");
- return;
- }
- absyToLayerNums[node] = new HashSet<int>();
- foreach (int layerNum in attrs)
- {
- if (layerNum == leastUnimplementedLayerNum || !AllCreatedLayerNums.Contains(layerNum))
- {
- Error(node, "Illegal layer number");
- }
- else if (layerNum > enclosingProcLayerNum)
- {
- Error(node, "The layer cannot be greater than the layer of enclosing procedure");
- }
- else if (maxLayerNum < layerNum && layerNum <= minLayerNum)
- {
- absyToLayerNums[node].Add(layerNum);
- }
- else
- {
- Error(node, string.Format("A variable being accessed in this specification is unavailable at layer {0}", layerNum));
- }
- }
- }
-
- public void Error(Absy node, string message)
- {
- checkingContext.Error(node, message);
- errorCount++;
- }
- }
-}
\ No newline at end of file diff --git a/Source/Concurrency/YieldTypeChecker.cs b/Source/Concurrency/YieldTypeChecker.cs index 95884626..ed59d3ad 100644 --- a/Source/Concurrency/YieldTypeChecker.cs +++ b/Source/Concurrency/YieldTypeChecker.cs @@ -1,363 +1,368 @@ -using System;
-using System.Collections;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using Microsoft.Boogie;
-using System.Diagnostics.Contracts;
-using Microsoft.Boogie.AbstractInterpretation;
-using Microsoft.Boogie.GraphUtil;
-using System.Diagnostics;
-
-namespace Microsoft.Boogie
-{
- class YieldTypeChecker
- {
- static List<Tuple<int, int, int>> ASpec;
- static List<Tuple<int, int, int>> BSpec;
- static List<Tuple<int, int, int>> CSpec;
- static YieldTypeChecker()
- {
- // initial: 0, final: 1
- ASpec = new List<Tuple<int,int,int>>();
- ASpec.Add(new Tuple<int, int, int>(0, 'Y', 1));
- ASpec.Add(new Tuple<int, int, int>(1, 'Y', 1));
- ASpec.Add(new Tuple<int, int, int>(1, 'B', 1));
- ASpec.Add(new Tuple<int, int, int>(1, 'R', 1));
- ASpec.Add(new Tuple<int, int, int>(1, 'L', 1));
- ASpec.Add(new Tuple<int, int, int>(1, 'A', 1));
- ASpec.Add(new Tuple<int, int, int>(0, 'P', 0));
- ASpec.Add(new Tuple<int, int, int>(1, 'P', 1));
-
- // initial: 1, final: 0
- BSpec = new List<Tuple<int, int, int>>();
- BSpec.Add(new Tuple<int, int, int>(1, 'Y', 0));
- BSpec.Add(new Tuple<int, int, int>(1, 'Y', 1));
- BSpec.Add(new Tuple<int, int, int>(1, 'B', 1));
- BSpec.Add(new Tuple<int, int, int>(1, 'R', 1));
- BSpec.Add(new Tuple<int, int, int>(1, 'L', 1));
- BSpec.Add(new Tuple<int, int, int>(1, 'A', 1));
- BSpec.Add(new Tuple<int, int, int>(0, 'P', 0));
- BSpec.Add(new Tuple<int, int, int>(1, 'P', 1));
-
- // initial: {0, 1}, final: {0, 1}
- CSpec = new List<Tuple<int,int,int>>();
- CSpec.Add(new Tuple<int, int, int>(0, 'B', 0));
- CSpec.Add(new Tuple<int, int, int>(0, 'R', 0));
- CSpec.Add(new Tuple<int, int, int>(0, 'Y', 0));
- CSpec.Add(new Tuple<int, int, int>(0, 'B', 1));
- CSpec.Add(new Tuple<int, int, int>(0, 'R', 1));
- CSpec.Add(new Tuple<int, int, int>(0, 'L', 1));
- CSpec.Add(new Tuple<int, int, int>(0, 'A', 1));
- CSpec.Add(new Tuple<int, int, int>(1, 'B', 1));
- CSpec.Add(new Tuple<int, int, int>(1, 'L', 1));
- CSpec.Add(new Tuple<int, int, int>(1, 'Y', 0));
- CSpec.Add(new Tuple<int, int, int>(0, 'P', 0));
- CSpec.Add(new Tuple<int, int, int>(1, 'P', 1));
- }
-
- private void IsYieldTypeSafe()
- {
- List<Tuple<int, int, int>> implEdges = new List<Tuple<int, int, int>>();
- foreach (Tuple<int, int> e in edgeLabels.Keys)
- {
- implEdges.Add(new Tuple<int, int, int>(e.Item1, edgeLabels[e], e.Item2));
- }
- //Console.WriteLine(PrintGraph(impl, implEdges, initialState, finalStates));
- ASpecCheck(implEdges);
- BSpecCheck(implEdges);
- CSpecCheck(implEdges);
- }
-
- private void ASpecCheck(List<Tuple<int, int, int>> implEdges)
- {
- Dictionary<int, HashSet<int>> initialConstraints = new Dictionary<int, HashSet<int>>();
- initialConstraints[initialState] = new HashSet<int>(new int[] { 0 });
- foreach (var finalState in finalStates)
- {
- initialConstraints[finalState] = new HashSet<int>(new int[] { 1 });
- }
- SimulationRelation<int, int, int> x = new SimulationRelation<int, int, int>(implEdges, ASpec, initialConstraints);
- Dictionary<int, HashSet<int>> simulationRelation = x.ComputeSimulationRelation();
- if (simulationRelation[initialState].Count == 0)
- {
- moverTypeChecker.Error(impl, string.Format("Implementation {0} fails simulation check A at layer {1}. An action must be preceded by a yield.\n", impl.Name, currLayerNum));
- }
- }
-
- private void BSpecCheck(List<Tuple<int, int, int>> implEdges)
- {
- Dictionary<int, HashSet<int>> initialConstraints = new Dictionary<int, HashSet<int>>();
- initialConstraints[initialState] = new HashSet<int>(new int[] { 1 });
- foreach (var finalState in finalStates)
- {
- initialConstraints[finalState] = new HashSet<int>(new int[] { 0 });
- }
- SimulationRelation<int, int, int> x = new SimulationRelation<int, int, int>(implEdges, BSpec, initialConstraints);
- Dictionary<int, HashSet<int>> simulationRelation = x.ComputeSimulationRelation();
- if (simulationRelation[initialState].Count == 0)
- {
- moverTypeChecker.Error(impl, string.Format("Implementation {0} fails simulation check B at layer {1}. An action must be succeeded by a yield.\n", impl.Name, currLayerNum));
- }
- }
-
- private void CSpecCheck(List<Tuple<int, int, int>> implEdges)
- {
- Dictionary<int, HashSet<int>> initialConstraints = new Dictionary<int, HashSet<int>>();
- foreach (Block block in loopHeaders)
- {
- if (!IsTerminatingLoopHeader(block))
- {
- initialConstraints[absyToNode[block]] = new HashSet<int>(new int[] { 0 });
- }
- }
- SimulationRelation<int, int, int> x = new SimulationRelation<int, int, int>(implEdges, CSpec, initialConstraints);
- Dictionary<int, HashSet<int>> simulationRelation = x.ComputeSimulationRelation();
- if (simulationRelation[initialState].Count == 0)
- {
- moverTypeChecker.Error(impl, string.Format("Implementation {0} fails simulation check C at layer {1}. Transactions must be separated by a yield.\n", impl.Name, currLayerNum));
- }
- }
-
- private bool IsTerminatingLoopHeader(Block block)
- {
- foreach (Cmd cmd in block.Cmds)
- {
- AssertCmd assertCmd = cmd as AssertCmd;
- if (assertCmd != null && QKeyValue.FindBoolAttribute(assertCmd.Attributes, "terminates") && moverTypeChecker.absyToLayerNums[assertCmd].Contains(currLayerNum))
- {
- return true;
- }
- }
- return false;
- }
-
- public static void PerformYieldSafeCheck(MoverTypeChecker moverTypeChecker)
- {
- foreach (var impl in moverTypeChecker.program.Implementations)
- {
- if (!moverTypeChecker.procToActionInfo.ContainsKey(impl.Proc)) continue;
- impl.PruneUnreachableBlocks();
- Graph<Block> implGraph = Program.GraphFromImpl(impl);
- implGraph.ComputeLoops();
- int specLayerNum = moverTypeChecker.procToActionInfo[impl.Proc].createdAtLayerNum;
- foreach (int layerNum in moverTypeChecker.AllCreatedLayerNums.Except(new int[] { moverTypeChecker.leastUnimplementedLayerNum }))
- {
- if (layerNum > specLayerNum) continue;
- YieldTypeChecker executor = new YieldTypeChecker(moverTypeChecker, impl, layerNum, implGraph.Headers);
- }
- }
- }
-
- int stateCounter;
- MoverTypeChecker moverTypeChecker;
- Implementation impl;
- int currLayerNum;
- Dictionary<Absy, int> absyToNode;
- Dictionary<int, Absy> nodeToAbsy;
- int initialState;
- HashSet<int> finalStates;
- Dictionary<Tuple<int, int>, int> edgeLabels;
- IEnumerable<Block> loopHeaders;
-
- private YieldTypeChecker(MoverTypeChecker moverTypeChecker, Implementation impl, int currLayerNum, IEnumerable<Block> loopHeaders)
- {
- this.moverTypeChecker = moverTypeChecker;
- this.impl = impl;
- this.currLayerNum = currLayerNum;
- this.loopHeaders = loopHeaders;
- this.stateCounter = 0;
- this.absyToNode = new Dictionary<Absy, int>();
- this.initialState = 0;
- this.finalStates = new HashSet<int>();
- this.edgeLabels = new Dictionary<Tuple<int, int>, int>();
-
- foreach (Block block in impl.Blocks)
- {
- absyToNode[block] = stateCounter;
- stateCounter++;
- foreach (Cmd cmd in block.Cmds)
- {
- absyToNode[cmd] = stateCounter;
- stateCounter++;
- }
- absyToNode[block.TransferCmd] = stateCounter;
- stateCounter++;
- if (block.TransferCmd is ReturnCmd)
- {
- finalStates.Add(absyToNode[block.TransferCmd]);
- }
- }
- foreach (Block block in impl.Blocks)
- {
- Absy blockEntry = block.Cmds.Count == 0 ? (Absy)block.TransferCmd : (Absy)block.Cmds[0];
- edgeLabels[new Tuple<int, int>(absyToNode[block], absyToNode[blockEntry])] = 'P';
-
- GotoCmd gotoCmd = block.TransferCmd as GotoCmd;
- if (gotoCmd == null) continue;
- foreach (Block successor in gotoCmd.labelTargets)
- {
- edgeLabels[new Tuple<int, int>(absyToNode[gotoCmd], absyToNode[successor])] = 'P';
- }
- }
-
- this.nodeToAbsy = new Dictionary<int, Absy>();
- foreach (KeyValuePair<Absy, int> state in absyToNode)
- {
- this.nodeToAbsy[state.Value] = state.Key;
- }
-
- ComputeGraph();
- IsYieldTypeSafe();
- }
-
- private void ComputeGraph()
- {
- foreach (Block block in impl.Blocks)
- {
- for (int i = 0; i < block.Cmds.Count; i++)
- {
- Cmd cmd = block.Cmds[i];
- int curr = absyToNode[cmd];
- int next = (i + 1 == block.Cmds.Count) ? absyToNode[block.TransferCmd] : absyToNode[block.Cmds[i + 1]];
- Tuple<int, int> edge = new Tuple<int, int>(curr, next);
- if (cmd is CallCmd)
- {
- CallCmd callCmd = cmd as CallCmd;
- if (callCmd.IsAsync)
- {
- ActionInfo actionInfo = moverTypeChecker.procToActionInfo[callCmd.Proc];
- if (currLayerNum <= actionInfo.createdAtLayerNum)
- edgeLabels[edge] = 'L';
- else
- edgeLabels[edge] = 'B';
- }
- else if (!moverTypeChecker.procToActionInfo.ContainsKey(callCmd.Proc))
- {
- edgeLabels[edge] = 'P';
- }
- else
- {
- MoverType moverType;
- ActionInfo actionInfo = moverTypeChecker.procToActionInfo[callCmd.Proc];
- if (actionInfo.createdAtLayerNum >= currLayerNum)
- {
- moverType = MoverType.Top;
- }
- else
- {
- AtomicActionInfo atomicActionInfo = actionInfo as AtomicActionInfo;
- if (atomicActionInfo == null)
- moverType = MoverType.Both;
- else
- moverType = atomicActionInfo.moverType;
- }
- switch (moverType)
- {
- case MoverType.Atomic:
- edgeLabels[edge] = 'A';
- break;
- case MoverType.Both:
- edgeLabels[edge] = 'B';
- break;
- case MoverType.Left:
- edgeLabels[edge] = 'L';
- break;
- case MoverType.Right:
- edgeLabels[edge] = 'R';
- break;
- case MoverType.Top:
- edgeLabels[edge] = 'Y';
- break;
- }
- }
- }
- else if (cmd is ParCallCmd)
- {
- ParCallCmd parCallCmd = cmd as ParCallCmd;
- bool isYield = false;
- bool isRightMover = true;
- bool isLeftMover = true;
- foreach (CallCmd callCmd in parCallCmd.CallCmds)
- {
- if (moverTypeChecker.procToActionInfo[callCmd.Proc].createdAtLayerNum >= currLayerNum)
- {
- isYield = true;
- }
- }
- if (isYield)
- {
- edgeLabels[edge] = 'Y';
- }
- else
- {
- foreach (CallCmd callCmd in parCallCmd.CallCmds)
- {
- ActionInfo actionInfo = moverTypeChecker.procToActionInfo[callCmd.Proc];
- isRightMover = isRightMover && actionInfo.IsRightMover;
- isLeftMover = isLeftMover && actionInfo.IsLeftMover;
- }
- if (isLeftMover && isRightMover)
- {
- edgeLabels[edge] = 'B';
- }
- else if (isLeftMover)
- {
- edgeLabels[edge] = 'L';
- }
- else if (isRightMover)
- {
- edgeLabels[edge] = 'R';
- }
- else
- {
- Debug.Assert(parCallCmd.CallCmds.Count == 1);
- edgeLabels[edge] = 'A';
- }
- }
- }
- else if (cmd is YieldCmd)
- {
- edgeLabels[edge] = 'Y';
- }
- else
- {
- edgeLabels[edge] = 'P';
- }
- }
- }
- }
-
- private static string PrintGraph(Implementation impl, List<Tuple<int, int, int>> edges, int initialState, HashSet<int> finalStates)
- {
- var s = new StringBuilder();
- s.AppendLine("\nImplementation " + impl.Proc.Name + " digraph G {");
- foreach (var e in edges)
- {
- string label = "P";
- switch (e.Item2)
- {
- case 'P': label = "P"; break;
- case 'Y': label = "Y"; break;
- case 'B': label = "B"; break;
- case 'R': label = "R"; break;
- case 'L': label = "L"; break;
- case 'A': label = "A"; break;
- default: Debug.Assert(false); break;
- }
- s.AppendLine(" \"" + e.Item1.ToString() + "\" -- " + label + " --> " + " \"" + e.Item3.ToString() + "\";");
- }
- s.AppendLine("}");
- s.AppendLine("Initial state: " + initialState);
- s.Append("Final states: ");
- bool first = true;
- foreach (int finalState in finalStates)
- {
- s.Append((first ? "" : ", ") + finalState);
- first = false;
- }
- s.AppendLine();
- return s.ToString();
- }
- }
-}
+using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Microsoft.Boogie; +using System.Diagnostics.Contracts; +using Microsoft.Boogie.AbstractInterpretation; +using Microsoft.Boogie.GraphUtil; +using System.Diagnostics; + +namespace Microsoft.Boogie +{ + class YieldTypeChecker + { + static List<Tuple<int, int, int>> ASpec; + static List<Tuple<int, int, int>> BSpec; + static List<Tuple<int, int, int>> CSpec; + static YieldTypeChecker() + { + // initial: 0, final: 1 + ASpec = new List<Tuple<int,int,int>>(); + ASpec.Add(new Tuple<int, int, int>(0, 'Y', 1)); + ASpec.Add(new Tuple<int, int, int>(1, 'Y', 1)); + ASpec.Add(new Tuple<int, int, int>(1, 'B', 1)); + ASpec.Add(new Tuple<int, int, int>(1, 'R', 1)); + ASpec.Add(new Tuple<int, int, int>(1, 'L', 1)); + ASpec.Add(new Tuple<int, int, int>(1, 'A', 1)); + ASpec.Add(new Tuple<int, int, int>(0, 'P', 0)); + ASpec.Add(new Tuple<int, int, int>(1, 'P', 1)); + + // initial: 1, final: 0 + BSpec = new List<Tuple<int, int, int>>(); + BSpec.Add(new Tuple<int, int, int>(1, 'Y', 0)); + BSpec.Add(new Tuple<int, int, int>(1, 'Y', 1)); + BSpec.Add(new Tuple<int, int, int>(1, 'B', 1)); + BSpec.Add(new Tuple<int, int, int>(1, 'R', 1)); + BSpec.Add(new Tuple<int, int, int>(1, 'L', 1)); + BSpec.Add(new Tuple<int, int, int>(1, 'A', 1)); + BSpec.Add(new Tuple<int, int, int>(0, 'P', 0)); + BSpec.Add(new Tuple<int, int, int>(1, 'P', 1)); + + // initial: {0, 1}, final: {0, 1} + CSpec = new List<Tuple<int,int,int>>(); + CSpec.Add(new Tuple<int, int, int>(0, 'B', 0)); + CSpec.Add(new Tuple<int, int, int>(0, 'R', 0)); + CSpec.Add(new Tuple<int, int, int>(0, 'Y', 0)); + CSpec.Add(new Tuple<int, int, int>(0, 'B', 1)); + CSpec.Add(new Tuple<int, int, int>(0, 'R', 1)); + CSpec.Add(new Tuple<int, int, int>(0, 'L', 1)); + CSpec.Add(new Tuple<int, int, int>(0, 'A', 1)); + CSpec.Add(new Tuple<int, int, int>(1, 'B', 1)); + CSpec.Add(new Tuple<int, int, int>(1, 'L', 1)); + CSpec.Add(new Tuple<int, int, int>(1, 'Y', 0)); + CSpec.Add(new Tuple<int, int, int>(0, 'P', 0)); + CSpec.Add(new Tuple<int, int, int>(1, 'P', 1)); + } + + private void IsYieldTypeSafe() + { + List<Tuple<int, int, int>> implEdges = new List<Tuple<int, int, int>>(); + foreach (Tuple<int, int> e in edgeLabels.Keys) + { + implEdges.Add(new Tuple<int, int, int>(e.Item1, edgeLabels[e], e.Item2)); + } + //Console.WriteLine(PrintGraph(impl, implEdges, initialState, finalStates)); + ASpecCheck(implEdges); + BSpecCheck(implEdges); + CSpecCheck(implEdges); + } + + private void ASpecCheck(List<Tuple<int, int, int>> implEdges) + { + Dictionary<int, HashSet<int>> initialConstraints = new Dictionary<int, HashSet<int>>(); + initialConstraints[initialState] = new HashSet<int>(new int[] { 0 }); + foreach (var finalState in finalStates) + { + initialConstraints[finalState] = new HashSet<int>(new int[] { 1 }); + } + SimulationRelation<int, int, int> x = new SimulationRelation<int, int, int>(implEdges, ASpec, initialConstraints); + Dictionary<int, HashSet<int>> simulationRelation = x.ComputeSimulationRelation(); + if (simulationRelation[initialState].Count == 0) + { + civlTypeChecker.Error(impl, string.Format("Implementation {0} fails simulation check A at layer {1}. An action must be preceded by a yield.\n", impl.Name, currLayerNum)); + } + } + + private void BSpecCheck(List<Tuple<int, int, int>> implEdges) + { + Dictionary<int, HashSet<int>> initialConstraints = new Dictionary<int, HashSet<int>>(); + initialConstraints[initialState] = new HashSet<int>(new int[] { 1 }); + foreach (var finalState in finalStates) + { + initialConstraints[finalState] = new HashSet<int>(new int[] { 0 }); + } + SimulationRelation<int, int, int> x = new SimulationRelation<int, int, int>(implEdges, BSpec, initialConstraints); + Dictionary<int, HashSet<int>> simulationRelation = x.ComputeSimulationRelation(); + if (simulationRelation[initialState].Count == 0) + { + civlTypeChecker.Error(impl, string.Format("Implementation {0} fails simulation check B at layer {1}. An action must be succeeded by a yield.\n", impl.Name, currLayerNum)); + } + } + + private void CSpecCheck(List<Tuple<int, int, int>> implEdges) + { + Dictionary<int, HashSet<int>> initialConstraints = new Dictionary<int, HashSet<int>>(); + foreach (Block block in loopHeaders) + { + if (!IsTerminatingLoopHeader(block)) + { + initialConstraints[absyToNode[block]] = new HashSet<int>(new int[] { 0 }); + } + } + SimulationRelation<int, int, int> x = new SimulationRelation<int, int, int>(implEdges, CSpec, initialConstraints); + Dictionary<int, HashSet<int>> simulationRelation = x.ComputeSimulationRelation(); + if (simulationRelation[initialState].Count == 0) + { + civlTypeChecker.Error(impl, string.Format("Implementation {0} fails simulation check C at layer {1}. Transactions must be separated by a yield.\n", impl.Name, currLayerNum)); + } + } + + private bool IsTerminatingLoopHeader(Block block) + { + foreach (Cmd cmd in block.Cmds) + { + AssertCmd assertCmd = cmd as AssertCmd; + if (assertCmd != null && QKeyValue.FindBoolAttribute(assertCmd.Attributes, "terminates") && civlTypeChecker.absyToLayerNums[assertCmd].Contains(currLayerNum)) + { + return true; + } + } + return false; + } + + public static void PerformYieldSafeCheck(CivlTypeChecker civlTypeChecker) + { + foreach (var impl in civlTypeChecker.program.Implementations) + { + if (!civlTypeChecker.procToActionInfo.ContainsKey(impl.Proc)) continue; + impl.PruneUnreachableBlocks(); + Graph<Block> implGraph = Program.GraphFromImpl(impl); + implGraph.ComputeLoops(); + int specLayerNum = civlTypeChecker.procToActionInfo[impl.Proc].createdAtLayerNum; + foreach (int layerNum in civlTypeChecker.AllLayerNums) + { + if (layerNum > specLayerNum) continue; + YieldTypeChecker executor = new YieldTypeChecker(civlTypeChecker, impl, layerNum, implGraph.Headers); + } + } + } + + int stateCounter; + CivlTypeChecker civlTypeChecker; + Implementation impl; + int currLayerNum; + Dictionary<Absy, int> absyToNode; + Dictionary<int, Absy> nodeToAbsy; + int initialState; + HashSet<int> finalStates; + Dictionary<Tuple<int, int>, int> edgeLabels; + IEnumerable<Block> loopHeaders; + + private YieldTypeChecker(CivlTypeChecker civlTypeChecker, Implementation impl, int currLayerNum, IEnumerable<Block> loopHeaders) + { + this.civlTypeChecker = civlTypeChecker; + this.impl = impl; + this.currLayerNum = currLayerNum; + this.loopHeaders = loopHeaders; + this.stateCounter = 0; + this.absyToNode = new Dictionary<Absy, int>(); + this.initialState = 0; + this.finalStates = new HashSet<int>(); + this.edgeLabels = new Dictionary<Tuple<int, int>, int>(); + + foreach (Block block in impl.Blocks) + { + absyToNode[block] = stateCounter; + stateCounter++; + foreach (Cmd cmd in block.Cmds) + { + absyToNode[cmd] = stateCounter; + stateCounter++; + } + absyToNode[block.TransferCmd] = stateCounter; + stateCounter++; + if (block.TransferCmd is ReturnCmd) + { + finalStates.Add(absyToNode[block.TransferCmd]); + } + } + foreach (Block block in impl.Blocks) + { + Absy blockEntry = block.Cmds.Count == 0 ? (Absy)block.TransferCmd : (Absy)block.Cmds[0]; + edgeLabels[new Tuple<int, int>(absyToNode[block], absyToNode[blockEntry])] = 'P'; + + GotoCmd gotoCmd = block.TransferCmd as GotoCmd; + if (gotoCmd == null) continue; + foreach (Block successor in gotoCmd.labelTargets) + { + edgeLabels[new Tuple<int, int>(absyToNode[gotoCmd], absyToNode[successor])] = 'P'; + } + } + + this.nodeToAbsy = new Dictionary<int, Absy>(); + foreach (KeyValuePair<Absy, int> state in absyToNode) + { + this.nodeToAbsy[state.Value] = state.Key; + } + + ComputeGraph(); + IsYieldTypeSafe(); + } + + private void ComputeGraph() + { + foreach (Block block in impl.Blocks) + { + for (int i = 0; i < block.Cmds.Count; i++) + { + Cmd cmd = block.Cmds[i]; + int curr = absyToNode[cmd]; + int next = (i + 1 == block.Cmds.Count) ? absyToNode[block.TransferCmd] : absyToNode[block.Cmds[i + 1]]; + Tuple<int, int> edge = new Tuple<int, int>(curr, next); + if (cmd is CallCmd) + { + CallCmd callCmd = cmd as CallCmd; + if (callCmd.IsAsync) + { + ActionInfo actionInfo = civlTypeChecker.procToActionInfo[callCmd.Proc]; + if (currLayerNum <= actionInfo.createdAtLayerNum) + edgeLabels[edge] = 'L'; + else + edgeLabels[edge] = 'B'; + } + else if (!civlTypeChecker.procToActionInfo.ContainsKey(callCmd.Proc)) + { + edgeLabels[edge] = 'P'; + } + else + { + MoverType moverType; + ActionInfo actionInfo = civlTypeChecker.procToActionInfo[callCmd.Proc]; + if (actionInfo.createdAtLayerNum >= currLayerNum) + { + moverType = MoverType.Top; + } + else + { + AtomicActionInfo atomicActionInfo = actionInfo as AtomicActionInfo; + if (atomicActionInfo == null) + moverType = MoverType.Both; + else + moverType = atomicActionInfo.moverType; + } + switch (moverType) + { + case MoverType.Atomic: + edgeLabels[edge] = 'A'; + break; + case MoverType.Both: + edgeLabels[edge] = 'B'; + break; + case MoverType.Left: + edgeLabels[edge] = 'L'; + break; + case MoverType.Right: + edgeLabels[edge] = 'R'; + break; + case MoverType.Top: + edgeLabels[edge] = 'Y'; + break; + } + } + } + else if (cmd is ParCallCmd) + { + ParCallCmd parCallCmd = cmd as ParCallCmd; + bool isYield = false; + bool isRightMover = true; + bool isLeftMover = true; + foreach (CallCmd callCmd in parCallCmd.CallCmds) + { + if (civlTypeChecker.procToActionInfo[callCmd.Proc].createdAtLayerNum >= currLayerNum) + { + isYield = true; + } + } + if (isYield) + { + edgeLabels[edge] = 'Y'; + } + else + { + int numAtomicActions = 0; + foreach (CallCmd callCmd in parCallCmd.CallCmds) + { + ActionInfo actionInfo = civlTypeChecker.procToActionInfo[callCmd.Proc]; + isRightMover = isRightMover && actionInfo.IsRightMover; + isLeftMover = isLeftMover && actionInfo.IsLeftMover; + if (actionInfo is AtomicActionInfo) + { + numAtomicActions++; + } + } + if (isLeftMover && isRightMover) + { + edgeLabels[edge] = 'B'; + } + else if (isLeftMover) + { + edgeLabels[edge] = 'L'; + } + else if (isRightMover) + { + edgeLabels[edge] = 'R'; + } + else + { + Debug.Assert(numAtomicActions == 1); + edgeLabels[edge] = 'A'; + } + } + } + else if (cmd is YieldCmd) + { + edgeLabels[edge] = 'Y'; + } + else + { + edgeLabels[edge] = 'P'; + } + } + } + } + + private static string PrintGraph(Implementation impl, List<Tuple<int, int, int>> edges, int initialState, HashSet<int> finalStates) + { + var s = new StringBuilder(); + s.AppendLine("\nImplementation " + impl.Proc.Name + " digraph G {"); + foreach (var e in edges) + { + string label = "P"; + switch (e.Item2) + { + case 'P': label = "P"; break; + case 'Y': label = "Y"; break; + case 'B': label = "B"; break; + case 'R': label = "R"; break; + case 'L': label = "L"; break; + case 'A': label = "A"; break; + default: Debug.Assert(false); break; + } + s.AppendLine(" \"" + e.Item1.ToString() + "\" -- " + label + " --> " + " \"" + e.Item3.ToString() + "\";"); + } + s.AppendLine("}"); + s.AppendLine("Initial state: " + initialState); + s.Append("Final states: "); + bool first = true; + foreach (int finalState in finalStates) + { + s.Append((first ? "" : ", ") + finalState); + first = false; + } + s.AppendLine(); + return s.ToString(); + } + } +} |