private void ReplacePreOrPostStateVars() { var sub = new Dictionary <Variable, Expr>(); foreach (var v in trc.allInParams) { sub[varCopies[v][0]] = Expr.Ident(v); } foreach (var v in trc.frame) { sub[varCopies[v][0]] = ExprHelper.Old(Expr.Ident(v)); } if (!trc.ignorePostState) { foreach (var v in trc.PostStateVars) { var lastCopy = varCopies[v].Last(); if (sub.ContainsKey(lastCopy)) { Debug.Assert(trc.frame.Contains(v) && lastCopy == varCopies[v][0]); pathExprs.Add(Expr.Eq(Expr.Ident(v), sub[lastCopy])); } // In case of conflict we prefer "v" instead of "old(v)" sub[lastCopy] = Expr.Ident(v); } } pathExprs = SubstitutionHelper.Apply(sub, pathExprs).ToList(); }
private Expr ElimPendingAsyncExpr(IdentifierExpr pa) { return(Expr.And( Expr.Or(elim.Keys.Select(a => ExprHelper.FunctionCall(a.pendingAsyncCtor.membership, pa))), Expr.Gt(Expr.Select(PAs, pa), Expr.Literal(0)) )); }
private Expr SubsetExpr(LinearDomain domain, Expr ie, Variable partition, int partitionCount) { Expr e = ExprHelper.FunctionCall(domain.mapConstInt, Expr.Literal(partitionCount)); e = ExprHelper.FunctionCall(domain.mapEqInt, Expr.Ident(partition), e); e = ExprHelper.FunctionCall(domain.mapImp, ie, e); e = Expr.Eq(e, ExprHelper.FunctionCall(domain.mapConstBool, Expr.True)); return e; }
private void ComputeWitnessedTransitionRelationExprs() { witnessedTransitionRelations = new List <Expr>(); Dictionary <Variable, List <WitnessFunction> > varToWitnesses = FrameWithWitnesses. Where(x => NotEliminatedVars.Contains(frameIntermediateCopy[x])). ToDictionary( x => frameIntermediateCopy[x], x => transitionRelationComputer.globalVarToWitnesses[(GlobalVariable)x]); foreach (var witnessSet in varToWitnesses.Values.CartesianProduct()) { Dictionary <Variable, Expr> witnessSubst = new Dictionary <Variable, Expr>(); foreach (Tuple <Variable, WitnessFunction> pair in Enumerable.Zip(varToWitnesses.Keys, witnessSet, Tuple.Create)) { WitnessFunction witnessFunction = pair.Item2; List <Expr> args = new List <Expr>(); foreach (var arg in witnessFunction.InputArgs) { Expr expr = null; switch (arg.Kind) { case WitnessFunction.InputArgumentKind.FIRST_ARG: // TODO: Add note on the reason of using second expr = Expr.Ident(second.Params. First(x => x.Name == second.Prefix + arg.Name)); break; case WitnessFunction.InputArgumentKind.SECOND_ARG: expr = Expr.Ident(first.Params. First(x => x.Name == first.Prefix + arg.Name)); break; case WitnessFunction.InputArgumentKind.PRE_STATE: expr = ExprHelper.Old(Expr.Ident( frame.First(x => x.Name == arg.Name))); break; case WitnessFunction.InputArgumentKind.POST_STATE: expr = Expr.Ident(frame.First(x => x.Name == arg.Name)); break; default: Debug.Assert(false); break; } args.Add(expr); } witnessSubst[pair.Item1] = ExprHelper.FunctionCall( witnessFunction.function, args.ToArray() ); } var subst = Substituter.SubstitutionFromHashtable(witnessSubst); witnessedTransitionRelations.Add( Substituter.Apply(subst, TransitionRelationExpr)); } }
public void AddTriggerAssumes(Program program) { foreach (Variable v in impl.LocVars) { var f = triggerFunctions[v]; program.AddTopLevelDeclaration(f); var assume = CmdHelper.AssumeCmd(ExprHelper.FunctionCall(f, Expr.Ident(v))); impl.Blocks[0].Cmds.Insert(0, assume); } }
public static void AddCheckers(CivlTypeChecker civlTypeChecker) { foreach (var action in civlTypeChecker.AllAtomicActions.Where(a => a.HasPendingAsyncs)) { var requires = action.gate.Select(g => new Requires(false, g.Expr)).ToList(); var PAs = Expr.Ident(action.impl.OutParams.Last(p => p.TypedIdent.Type.Equals(civlTypeChecker.pendingAsyncMultisetType))); var paBound = civlTypeChecker.BoundVariable("pa", civlTypeChecker.pendingAsyncType); var pa = Expr.Ident(paBound); var nonnegativeExpr = ExprHelper.ForallExpr(new List <Variable> { paBound }, Expr.Ge(Expr.Select(PAs, pa), Expr.Literal(0))); var correctTypeExpr = ExprHelper.ForallExpr(new List <Variable> { paBound }, Expr.Imp( Expr.Gt(Expr.Select(PAs, pa), Expr.Literal(0)), Expr.Or(action.pendingAsyncs.Select(a => ExprHelper.FunctionCall(a.pendingAsyncCtor.membership, pa))))); CivlUtil.ResolveAndTypecheck(nonnegativeExpr); CivlUtil.ResolveAndTypecheck(correctTypeExpr); var cmds = new List <Cmd> { CmdHelper.CallCmd( action.proc, action.impl.InParams.Select(Expr.Ident).ToList <Expr>(), action.impl.OutParams.Select(Expr.Ident).ToList()), CmdHelper.AssertCmd( action.proc.tok, nonnegativeExpr, $"Action {action.proc.Name} might create negative pending asyncs"), CmdHelper.AssertCmd( action.proc.tok, correctTypeExpr, $"Action {action.proc.Name} might create undeclared pending asyncs") }; var blocks = new List <Block>() { BlockHelper.Block("init", cmds) }; var proc = DeclHelper.Procedure(civlTypeChecker.AddNamePrefix($"PendingAsyncChecker_{action.proc.Name}"), action.impl.InParams, action.impl.OutParams, requires, action.proc.Modifies, new List <Ensures>()); var impl = DeclHelper.Implementation(proc, proc.InParams, proc.OutParams, new List <Variable>(), blocks); civlTypeChecker.program.AddTopLevelDeclaration(proc); civlTypeChecker.program.AddTopLevelDeclaration(impl); } }
public Tuple <Procedure, Implementation> GenerateStepChecker(AtomicAction pendingAsync, Function pendingAsyncAdd) { this.checkName = "step"; var requires = invariantAction.gate.Select(g => new Requires(false, g.Expr)).ToList(); var ensures = new List <Ensures> { GetEnsures(GetTransitionRelation(invariantAction)) }; var locals = new List <Variable>(); if (!HasChoice) { locals.Add(choice.Decl); } List <Cmd> cmds = new List <Cmd>(); cmds.Add(GetCallCmd(invariantAction)); cmds.Add(CmdHelper.AssumeCmd(ExprHelper.FunctionCall(pendingAsync.pendingAsyncCtor.membership, choice))); cmds.Add(CmdHelper.AssumeCmd(Expr.Gt(Expr.Select(PAs, choice), Expr.Literal(0)))); cmds.Add(RemoveChoice); AtomicAction abs = elim[pendingAsync]; Dictionary <Variable, Expr> map = new Dictionary <Variable, Expr>(); List <Expr> inputExprs = new List <Expr>(); for (int i = 0; i < abs.impl.InParams.Count; i++) { var pendingAsyncParam = ExprHelper.FunctionCall(pendingAsync.pendingAsyncCtor.selectors[i], choice); map[abs.impl.InParams[i]] = pendingAsyncParam; inputExprs.Add(pendingAsyncParam); } var subst = Substituter.SubstitutionFromHashtable(map); cmds.AddRange(GetGateAsserts(abs, subst)); List <IdentifierExpr> outputVars = new List <IdentifierExpr>(); if (abs.HasPendingAsyncs) { locals.Add(newPAs.Decl); outputVars.Add(newPAs); } cmds.Add(CmdHelper.CallCmd(abs.proc, inputExprs, outputVars)); if (abs.HasPendingAsyncs) { cmds.Add(AddNewPAs(pendingAsyncAdd)); } var blocks = new List <Block> { new Block(Token.NoToken, pendingAsync.proc.Name, cmds, CmdHelper.ReturnCmd) }; return(GetCheckerTuple(requires, ensures, locals, blocks, "_" + abs.proc.Name)); }
private static Expr PermissionMultiset(LinearDomain domain, IEnumerable<Expr> exprs) { var terms = exprs.Select(x => ExprHelper.FunctionCall(domain.mapIteInt, ExprHelper.FunctionCall(domain.collectors[x.Type], x), domain.MapConstInt(1), domain.MapConstInt(0))).ToList<Expr>(); if (terms.Count == 0) return domain.MapConstInt(0); return terms.Aggregate((x, y) => ExprHelper.FunctionCall(domain.mapAdd, x, y)); }
private static List<Expr> PendingAsyncLinearParams(LinearTypeChecker linearTypeChecker, LinearDomain domain, AtomicAction pendingAsync, IdentifierExpr pa) { var pendingAsyncLinearParams = new List<Expr>(); for (int i = 0; i < pendingAsync.proc.InParams.Count; i++) { var inParam = pendingAsync.proc.InParams[i]; if (linearTypeChecker.FindDomainName(inParam) == domain.domainName && InKinds.Contains(linearTypeChecker.FindLinearKind(inParam))) { var pendingAsyncParam = ExprHelper.FunctionCall(pendingAsync.pendingAsyncCtor.selectors[i], pa); pendingAsyncLinearParams.Add(pendingAsyncParam); } } return pendingAsyncLinearParams; }
private void CalculatePathExpression() { pathExprs = new List <Expr>(); foreach (var expr in assumes) { ExprHelper.FlattenAnd(expr, pathExprs); } foreach (var assignment in assignments) { // If a variable is forward and backward assigned, we might // have a substitution for the lhs here. if (!varToExpr.TryGetValue(assignment.Var, out Expr x)) { x = Expr.Ident(assignment.Var); } pathExprs.Add(Expr.Eq(x, assignment.Expr)); } }
private void ComputeTransitionRelationExpr() { CalculatePathExpression(); AddBoundVariablesForRemainingVars(); ReplacePreOrPostStateVars(); TransitionRelationExpr = Expr.And(pathExprs); if (trc.IsJoint) { ComputeWitnessedTransitionRelationExprs(); if (witnessedTransitionRelations.Count > 0) { TransitionRelationExpr = Expr.Or(witnessedTransitionRelations); } } if (existsVarMap.Any()) { Trigger trigger = null; if (trc.IsJoint) { var exprs = new List <Expr>(); foreach (var v in existsVarMap.Keys) { var orig = copyToOriginalVar[v]; if (v == varCopies[orig].First() && trc.triggers.ContainsKey(orig)) { var f = trc.triggers[orig]; exprs.Add(ExprHelper.FunctionCall(f, Expr.Ident(existsVarMap[v]))); } } if (exprs.Count == existsVarMap.Count) { trigger = new Trigger(Token.NoToken, true, exprs); } } TransitionRelationExpr = ExprHelper.ExistsExpr( existsVarMap.Values.ToList <Variable>(), trigger, TransitionRelationExpr); } }
private void ComputeWitnessedTransitionRelationExprs() { witnessedTransitionRelations = new List <Expr>(); Dictionary <Variable, List <CommutativityWitness> > varToWitnesses = trc.FrameWithWitnesses. Where(x => NotEliminatedVars.Contains(frameIntermediateCopy[x])). ToDictionary( x => frameIntermediateCopy[x], x => trc.globalVarToWitnesses[(GlobalVariable)x]); foreach (var witnessSet in varToWitnesses.Values.CartesianProduct()) { Dictionary <Variable, Expr> witnessSubst = new Dictionary <Variable, Expr>(); foreach (Tuple <Variable, CommutativityWitness> pair in Enumerable.Zip(varToWitnesses.Keys, witnessSet, Tuple.Create)) { CommutativityWitness witness = pair.Item2; witnessSubst[pair.Item1] = ExprHelper.FunctionCall( witness.function, witness.args.ToArray() ); } witnessedTransitionRelations.Add( SubstitutionHelper.Apply(witnessSubst, TransitionRelationExpr)); } }
public static void AddCheckers(CivlTypeChecker ctc) { foreach (var action in ctc.AllAtomicActions.Where(a => a.HasPendingAsyncs)) { var requires = action.gate.Select(g => new Requires(false, g.Expr)).ToList(); var cmds = new List <Cmd> { CmdHelper.CallCmd( action.proc, action.impl.InParams.Select(Expr.Ident).ToList <Expr>(), action.impl.OutParams.Select(Expr.Ident).ToList()) }; var blocks = new List <Block>() { new Block(Token.NoToken, "init", cmds, CmdHelper.ReturnCmd) }; var PAs = Expr.Ident(action.impl.OutParams.Last(p => p.TypedIdent.Type.Equals(ctc.pendingAsyncMultisetType))); var paBound = VarHelper.BoundVariable("pa", ctc.pendingAsyncType); var pa = Expr.Ident(paBound); var nonnegativeExpr = new ForallExpr(Token.NoToken, new List <Variable> { paBound }, Expr.Ge(Expr.Select(PAs, pa), Expr.Literal(0))); var correctTypeExpr = new ForallExpr(Token.NoToken, new List <Variable> { paBound }, Expr.Imp( Expr.Gt(Expr.Select(PAs, pa), Expr.Literal(0)), Expr.Or(action.pendingAsyncs.Select(a => ExprHelper.FunctionCall(a.pendingAsyncCtor.membership, pa))))); var ensures = new List <Ensures> { new Ensures(false, nonnegativeExpr) { ErrorData = $"Action {action.proc.Name} might create negative pending asyncs" }, new Ensures(false, correctTypeExpr) { ErrorData = $"Action {action.proc.Name} might create undeclared pending asyncs" }, }; CivlUtil.ResolveAndTypecheck(ensures); var proc = new Procedure(Token.NoToken, $"PendingAsyncChecker_{action.proc.Name}", new List <TypeVariable>(), action.impl.InParams, action.impl.OutParams, requires, action.proc.Modifies, ensures); var impl = new Implementation(Token.NoToken, proc.Name, proc.TypeParameters, proc.InParams, proc.OutParams, new List <Variable>(), blocks) { Proc = proc }; ctc.program.AddTopLevelDeclaration(proc); ctc.program.AddTopLevelDeclaration(impl); } }
private void CreateCommutativityChecker(AtomicAction first, AtomicAction second) { if (first == second && first.firstImpl.InParams.Count == 0 && first.firstImpl.OutParams.Count == 0) { return; } if (first.TriviallyCommutesWith(second)) { return; } if (!commutativityCheckerCache.Add(Tuple.Create(first, second))) { return; } string checkerName = $"CommutativityChecker_{first.proc.Name}_{second.proc.Name}"; 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 = new List <Requires> { DisjointnessRequires( first.firstImpl.InParams.Union(second.secondImpl.InParams) .Where(v => linearTypeChecker.FindLinearKind(v) != LinearKind.LINEAR_OUT), frame) }; foreach (AssertCmd assertCmd in Enumerable.Union(first.firstGate, second.secondGate)) { requires.Add(new Requires(false, assertCmd.Expr)); } var witnesses = civlTypeChecker.commutativityHints.GetWitnesses(first, second); var transitionRelation = TransitionRelationComputation.Commutativity(second, first, frame, witnesses); List <Cmd> cmds = new List <Cmd> { new CallCmd(Token.NoToken, first.proc.Name, first.firstImpl.InParams.Select(Expr.Ident).ToList <Expr>(), first.firstImpl.OutParams.Select(Expr.Ident).ToList() ) { Proc = first.proc }, new CallCmd(Token.NoToken, second.proc.Name, second.secondImpl.InParams.Select(Expr.Ident).ToList <Expr>(), second.secondImpl.OutParams.Select(Expr.Ident).ToList() ) { Proc = second.proc } }; foreach (var lemma in civlTypeChecker.commutativityHints.GetLemmas(first, second)) { cmds.Add(CmdHelper.AssumeCmd(ExprHelper.FunctionCall(lemma.function, lemma.args.ToArray()))); } var block = new Block(Token.NoToken, "init", cmds, new ReturnCmd(Token.NoToken)); var secondInParamsFiltered = second.secondImpl.InParams.Where(v => linearTypeChecker.FindLinearKind(v) != LinearKind.LINEAR_IN); IEnumerable <Expr> linearityAssumes = Enumerable.Union( linearTypeChecker.DisjointnessExprForEachDomain(first.firstImpl.OutParams.Union(secondInParamsFiltered) .Union(frame)), linearTypeChecker.DisjointnessExprForEachDomain(first.firstImpl.OutParams.Union(second.secondImpl.OutParams) .Union(frame))); // TODO: add further disjointness expressions? Ensures ensureCheck = new Ensures(first.proc.tok, false, Expr.Imp(Expr.And(linearityAssumes), transitionRelation), null) { ErrorData = $"Commutativity check between {first.proc.Name} and {second.proc.Name} failed" }; List <Ensures> ensures = new List <Ensures> { ensureCheck }; List <Variable> inputs = Enumerable.Union(first.firstImpl.InParams, second.secondImpl.InParams).ToList(); List <Variable> outputs = Enumerable.Union(first.firstImpl.OutParams, second.secondImpl.OutParams).ToList(); AddChecker(checkerName, inputs, outputs, new List <Variable>(), requires, ensures, new List <Block> { block }); }
public Expr MapEqTrue(Expr expr) { return Expr.Eq(expr, ExprHelper.FunctionCall(mapConstBool, Expr.True)); }
public Expr MapConstInt(int value) { return ExprHelper.FunctionCall(mapConstInt, Expr.Literal(value)); }
public Tuple <Procedure, Implementation> GenerateStepChecker(Function pendingAsyncAdd) { this.checkName = "step"; var requires = invariantAction.gate.Select(g => new Requires(false, g.Expr)).ToList(); var ensures = new List <Ensures> { GetEnsures(GetTransitionRelation(invariantAction)) }; var locals = new List <Variable>(); if (elim.Values.Any(a => a.HasPendingAsyncs)) { locals.Add(newPAs.Decl); } List <Block> blocks = new List <Block>(); foreach (var pendingAsync in elim.Keys) { AtomicAction abs = elim[pendingAsync]; Dictionary <Variable, Expr> map = new Dictionary <Variable, Expr>(); List <Expr> inputExprs = new List <Expr>(); for (int i = 0; i < abs.impl.InParams.Count; i++) { var pendingAsyncParam = ExprHelper.FunctionCall(pendingAsync.pendingAsyncCtor.selectors[i], choice); map[abs.impl.InParams[i]] = pendingAsyncParam; inputExprs.Add(pendingAsyncParam); } var subst = Substituter.SubstitutionFromHashtable(map); List <IdentifierExpr> outputVars = new List <IdentifierExpr>(); if (abs.HasPendingAsyncs) { outputVars.Add(newPAs); } List <Cmd> cmds = new List <Cmd>(); cmds.Add(CmdHelper.AssumeCmd(ExprHelper.FunctionCall(pendingAsync.pendingAsyncCtor.membership, choice))); cmds.AddRange(GetGateAsserts(abs, subst)); cmds.Add(CmdHelper.CallCmd(abs.proc, inputExprs, outputVars)); if (abs.HasPendingAsyncs) { cmds.Add(AddNewPAs(pendingAsyncAdd)); } var block = new Block(Token.NoToken, pendingAsync.proc.Name, cmds, CmdHelper.ReturnCmd); blocks.Add(block); } { List <Cmd> cmds = new List <Cmd>(); cmds.Add(GetCallCmd(invariantAction)); if (HasChoice) { cmds.Add(new AssumeCmd(Token.NoToken, ValidChoiceExpr)); cmds.Add( new AssertCmd(Token.NoToken, ElimPendingAsyncExpr(choice)) { ErrorData = $"Failed to validate choice in IS of {inputAction.proc.Name}" } ); } else { locals.Add(choice.Decl); cmds.Add(new AssumeCmd(Token.NoToken, ElimPendingAsyncExpr(choice))); } cmds.Add(RemoveChoice); var initBlock = new Block(Token.NoToken, "init", cmds, new GotoCmd(Token.NoToken, blocks.ToList())); blocks.Insert(0, initBlock); } return(GetCheckerTuple(requires, ensures, locals, blocks)); }
private Dictionary <Implementation, List <Cmd> > CreatePreconditions( LinearPermissionInstrumentation linearPermissionInstrumentation) { var implToInitCmds = new Dictionary <Implementation, List <Cmd> >(); foreach (var impl in absyMap.Keys.OfType <Implementation>()) { var initCmds = new List <Cmd>(); if (civlTypeChecker.GlobalVariables.Count() > 0) { initCmds.Add(CmdHelper.HavocCmd( civlTypeChecker.GlobalVariables.Select(v => Expr.Ident(v)).ToList())); linearPermissionInstrumentation.DisjointnessExprs(impl, true).ForEach( expr => initCmds.Add(CmdHelper.AssumeCmd(expr))); Substitution procToImplInParams = Substituter.SubstitutionFromHashtable(impl.Proc.InParams .Zip(impl.InParams).ToDictionary(x => x.Item1, x => (Expr)Expr.Ident(x.Item2))); impl.Proc.Requires.ForEach(req => initCmds.Add(new AssumeCmd(req.tok, Substituter.Apply(procToImplInParams, req.Condition)))); foreach (var callCmd in GetYieldingProc(impl).yieldRequires) { var yieldInvariant = civlTypeChecker.procToYieldInvariant[callCmd.Proc]; if (layerNum == yieldInvariant.LayerNum) { Substitution callFormalsToActuals = Substituter.SubstitutionFromHashtable(callCmd.Proc.InParams .Zip(callCmd.Ins) .ToDictionary(x => x.Item1, x => (Expr)ExprHelper.Old(x.Item2))); callCmd.Proc.Requires.ForEach(req => initCmds.Add(new AssumeCmd(req.tok, Substituter.Apply(procToImplInParams, Substituter.Apply(callFormalsToActuals, req.Condition))))); } } } implToInitCmds[impl] = initCmds; } return(implToInitCmds); }
private AssignCmd AddNewPAs(Function pendingAsyncAdd) { return(AssignCmd.SimpleAssign(Token.NoToken, PAs, ExprHelper.FunctionCall(pendingAsyncAdd, PAs, newPAs))); }
private static void AddChecker(CivlTypeChecker civlTypeChecker, Action action, List<Declaration> decls) { var linearTypeChecker = civlTypeChecker.linearTypeChecker; // Note: The implementation should be used as the variables in the // gate are bound to implementation and not to the procedure. Implementation impl = action.impl; List<Variable> inputs = impl.InParams; List<Variable> outputs = impl.OutParams; List<Variable> locals = new List<Variable>(2); var paLocal1 = civlTypeChecker.LocalVariable("pa1", civlTypeChecker.pendingAsyncType); var paLocal2 = civlTypeChecker.LocalVariable("pa2", civlTypeChecker.pendingAsyncType); var pa1 = Expr.Ident(paLocal1); var pa2 = Expr.Ident(paLocal2); if (civlTypeChecker.pendingAsyncType != null) { locals.Add(paLocal1); locals.Add(paLocal2); } List<Requires> requires = action.gate.Select(a => new Requires(false, a.Expr)).ToList(); List<LinearityCheck> linearityChecks = new List<LinearityCheck>(); foreach (var domain in linearTypeChecker.linearDomains.Values) { // Linear in vars var inVars = inputs.Union(action.modifiedGlobalVars) .Where(x => linearTypeChecker.FindDomainName(x) == domain.domainName) .Where(x => InKinds.Contains(linearTypeChecker.FindLinearKind(x))) .Select(Expr.Ident) .ToList(); // Linear out vars var outVars = inputs.Union(outputs).Union(action.modifiedGlobalVars) .Where(x => linearTypeChecker.FindDomainName(x) == domain.domainName) .Where(x => OutKinds.Contains(linearTypeChecker.FindLinearKind(x))) .Select(Expr.Ident) .ToList(); // First kind // Permissions in linear output variables are a subset of permissions in linear input variables. if (outVars.Count > 0) { linearityChecks.Add(new LinearityCheck( null, OutPermsSubsetInPerms(domain, inVars, outVars), $"Potential linearity violation in outputs for domain {domain.domainName}.", "variables")); } if (action is AtomicAction atomicAction && atomicAction.HasPendingAsyncs) { var PAs = Expr.Ident(atomicAction.impl.OutParams.Last()); foreach (var pendingAsync in atomicAction.pendingAsyncs) { var pendingAsyncLinearParams = PendingAsyncLinearParams(linearTypeChecker, domain, pendingAsync, pa1); if (pendingAsyncLinearParams.Count == 0) continue; // Second kind // Permissions in linear output variables + linear inputs of a single pending async // are a subset of permissions in linear input variables. var exactlyOnePA = Expr.And( ExprHelper.FunctionCall(pendingAsync.pendingAsyncCtor.membership, pa1), Expr.Eq(Expr.Select(PAs, pa1), Expr.Literal(1))); var outSubsetInExpr = OutPermsSubsetInPerms(domain, inVars, pendingAsyncLinearParams.Union(outVars)); linearityChecks.Add(new LinearityCheck( exactlyOnePA, outSubsetInExpr, $"Potential linearity violation in outputs and pending async of {pendingAsync.proc.Name} for domain {domain.domainName}.", $"single_{pendingAsync.proc.Name}")); // Third kind // If there are two identical pending asyncs, then their input permissions mut be empty. var twoIdenticalPAs = Expr.And( ExprHelper.FunctionCall(pendingAsync.pendingAsyncCtor.membership, pa1), Expr.Ge(Expr.Select(PAs, pa1), Expr.Literal(2))); var emptyPerms = OutPermsSubsetInPerms(domain, Enumerable.Empty<Expr>(), pendingAsyncLinearParams); linearityChecks.Add(new LinearityCheck( twoIdenticalPAs, emptyPerms, $"Potential linearity violation in identical pending asyncs of {pendingAsync.proc.Name} for domain {domain.domainName}.", $"identical_{pendingAsync.proc.Name}")); } var pendingAsyncs = atomicAction.pendingAsyncs.ToList(); for (int i = 0; i < pendingAsyncs.Count; i++) { var pendingAsync1 = pendingAsyncs[i]; for (int j = i; j < pendingAsyncs.Count; j++) { var pendingAsync2 = pendingAsyncs[j]; var pendingAsyncLinearParams1 = PendingAsyncLinearParams(linearTypeChecker, domain, pendingAsync1, pa1); var pendingAsyncLinearParams2 = PendingAsyncLinearParams(linearTypeChecker, domain, pendingAsync2, pa2); if (pendingAsyncLinearParams1.Count == 0 || pendingAsyncLinearParams2.Count == 0) continue; // Fourth kind // Input permissions of two non-identical pending asyncs (possibly of the same action) // are a subset of permissions in linear input variables. var membership = Expr.And( Expr.Neq(pa1, pa2), Expr.And( ExprHelper.FunctionCall(pendingAsync1.pendingAsyncCtor.membership, pa1), ExprHelper.FunctionCall(pendingAsync2.pendingAsyncCtor.membership, pa2))); var existing = Expr.And( Expr.Ge(Expr.Select(PAs, pa1), Expr.Literal(1)), Expr.Ge(Expr.Select(PAs, pa2), Expr.Literal(1))); var noDuplication = OutPermsSubsetInPerms(domain, inVars, pendingAsyncLinearParams1.Union(pendingAsyncLinearParams2)); linearityChecks.Add(new LinearityCheck( Expr.And(membership, existing), noDuplication, $"Potential lnearity violation in pending asyncs of {pendingAsync1.proc.Name} and {pendingAsync2.proc.Name} for domain {domain.domainName}.", $"distinct_{pendingAsync1.proc.Name}_{pendingAsync2.proc.Name}")); } } } } if (linearityChecks.Count == 0) return; // Create checker blocks List<Block> checkerBlocks = new List<Block>(linearityChecks.Count); foreach (var lc in linearityChecks) { List<Cmd> cmds = new List<Cmd>(2); if (lc.assume != null) { cmds.Add(CmdHelper.AssumeCmd(lc.assume)); } cmds.Add(new AssertCmd(action.proc.tok, lc.assert) { ErrorData = lc.message }); var block = new Block(Token.NoToken, lc.name, cmds, CmdHelper.ReturnCmd); CivlUtil.ResolveAndTypecheck(block, ResolutionContext.State.Two); checkerBlocks.Add(block); } // Create init blocks List<Block> blocks = new List<Block>(linearityChecks.Count + 1); blocks.Add( new Block( Token.NoToken, "init", new List<Cmd> { CmdHelper.CallCmd(action.proc, inputs, outputs) }, new GotoCmd(Token.NoToken, checkerBlocks))); blocks.AddRange(checkerBlocks); // Create the whole check procedure string checkerName = civlTypeChecker.AddNamePrefix($"LinearityChecker_{action.proc.Name}"); Procedure linCheckerProc = new Procedure(Token.NoToken, checkerName, new List<TypeVariable>(), inputs, outputs, requires, action.proc.Modifies, new List<Ensures>()); Implementation linCheckImpl = new Implementation(Token.NoToken, checkerName, new List<TypeVariable>(), inputs, outputs, locals, blocks); linCheckImpl.Proc = linCheckerProc; decls.Add(linCheckImpl); decls.Add(linCheckerProc); }