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; }
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 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); }
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); }
private void CreateFailurePreservationChecker(Program program, AtomicActionInfo first, AtomicActionInfo second) { if (first.gateUsedGlobalVars.Intersect(second.modifiedGlobalVars).Count() == 0) { return; } if (!failurePreservationCheckerCache.Add(new Tuple <AtomicActionInfo, AtomicActionInfo>(first, second))) { return; } List <Variable> inputs = Enumerable.Union(first.thatInParams, second.thisInParams).ToList(); List <Variable> outputs = Enumerable.Union(first.thatOutParams, second.thisOutParams).ToList(); List <Variable> locals = new List <Variable>(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 = new List <Requires>(); requires.Add(DisjointnessRequires(program, first.thatInParams.Union(second.thisInParams), frame)); Expr gateExpr = Expr.Not(Expr.And(first.thatGate.Select(a => a.Expr))); gateExpr.Type = Type.Bool; // necessary? requires.Add(new Requires(false, gateExpr)); foreach (AssertCmd assertCmd in second.thisGate) { requires.Add(new Requires(false, assertCmd.Expr)); } IEnumerable <Expr> linearityAssumes = DisjointnessExpr(program, first.thatInParams.Union(second.thisOutParams), frame); Ensures ensureCheck = new Ensures(false, Expr.Imp(Expr.And(linearityAssumes), gateExpr)); ensureCheck.ErrorData = string.Format("Gate failure of {0} not preserved by {1}", first.proc.Name, second.proc.Name); List <Ensures> ensures = new List <Ensures> { ensureCheck }; string checkerName = string.Format("FailurePreservationChecker_{0}_{1}", first.proc.Name, second.proc.Name); List <IdentifierExpr> globalVars = civlTypeChecker.SharedVariables.Select(x => Expr.Ident(x)).ToList(); 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 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 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 = new List <Requires>(); requires.Add(DisjointnessRequires(program, second.thisInParams, 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(); Ensures ensureCheck = new Ensures(false, ensuresExpr); ensureCheck.ErrorData = string.Format("{0} is blocking", second.proc.Name); List <Ensures> ensures = new List <Ensures> { ensureCheck }; List <Block> blocks = new List <Block> { new Block(Token.NoToken, "L", new List <Cmd>(), new ReturnCmd(Token.NoToken)) }; string checkerName = string.Format("NonBlockingChecker_{0}", second.proc.Name); List <IdentifierExpr> globalVars = civlTypeChecker.SharedVariables.Select(x => Expr.Ident(x)).ToList(); 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); }
public TransitionRelationComputation(Program program, AtomicActionInfo first, AtomicActionInfo second, HashSet<Variable> frame, HashSet<Variable> postExistVars) { this.program = program; this.first = first; this.second = second; this.postExistVars = postExistVars; this.frame = frame; this.existsVars = new Dictionary<Variable, Variable>(); this.firstExistsVars = new HashSet<Variable>( first != null ? first.thatOutParams.Union(first.thatAction.LocVars) : Enumerable.Empty<Variable>()); this.secondExistsVars = new HashSet<Variable>(second.thisOutParams.Union(second.thisAction.LocVars)); this.cmdStack = new Stack<Cmd>(); this.paths = new List<PathInfo>(); EnumeratePaths(); }
public TransitionRelationComputation(Program program, AtomicActionInfo first, AtomicActionInfo second, HashSet <Variable> frame, HashSet <Variable> postExistVars) { this.program = program; this.first = first; this.second = second; this.postExistVars = postExistVars; this.frame = frame; this.existsVars = new Dictionary <Variable, Variable>(); this.firstExistsVars = new HashSet <Variable>( first != null ? first.thatOutParams.Union(first.thatAction.LocVars) : Enumerable.Empty <Variable>()); this.secondExistsVars = new HashSet <Variable>(second.thisOutParams.Union(second.thisAction.LocVars)); this.cmdStack = new Stack <Cmd>(); this.paths = new List <PathInfo>(); EnumeratePaths(); }
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 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 TransitionRelationComputation(Program program, AtomicActionInfo first, AtomicActionInfo second, HashSet <Variable> frame, HashSet <Variable> postExistVars) { this.postExistVars = postExistVars; this.frame = frame; TransitionRelationComputationHelper(program, first, second); }
public TransitionRelationComputation(Program program, AtomicActionInfo second, HashSet <Variable> frame, HashSet <Variable> postExistVars) : this(program, null, second, frame, postExistVars) { }
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 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 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; }
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 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 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'; } } } }
public TransitionRelationComputation(Program program, AtomicActionInfo second, HashSet<Variable> frame, HashSet<Variable> postExistVars) : this(program, null, second, frame, postExistVars) { }
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.isExtern && actionInfo.hasImplementation) { Error(proc, "Extern procedure cannot have an implementation"); continue; } if (actionInfo.isExtern || actionInfo.hasImplementation) continue; if (leastUnimplementedLayerNum == int.MaxValue) { leastUnimplementedLayerNum = actionInfo.createdAtLayerNum; } else if (leastUnimplementedLayerNum != actionInfo.createdAtLayerNum) { 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); foreach (Procedure proc in program.Procedures) { if (procToActionInfo.ContainsKey(proc)) continue; foreach (var ie in proc.Modifies) { if (!SharedVariables.Contains(ie.Decl)) continue; Error(proc, "A ghost procedure must not modify a global variable with layer annotation"); } } if (errorCount > 0) return; YieldTypeChecker.PerformYieldSafeCheck(this); new LayerEraser().VisitProgram(program); }
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 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); }
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 CreateCommutativityChecker(Program program, AtomicActionInfo first, AtomicActionInfo second) { if (first == second && first.thatInParams.Count == 0 && first.thatOutParams.Count == 0) return; if (first.CommutesWith(second)) return; if (!commutativityCheckerCache.Add(new Tuple<AtomicActionInfo, AtomicActionInfo>(first, second))) return; List<Variable> inputs = Enumerable.Union(first.thatInParams, second.thisInParams).ToList(); List<Variable> outputs = Enumerable.Union(first.thatOutParams, second.thisOutParams).ToList(); List<Variable> locals = Enumerable.Union(first.thatAction.LocVars, second.thisAction.LocVars).ToList(); List<Block> firstBlocks = CloneBlocks(first.thatAction.Blocks); List<Block> secondBlocks = CloneBlocks(second.thisAction.Blocks); foreach (Block b in firstBlocks.Where(b => b.TransferCmd is ReturnCmd)) { List<Block> bs = new List<Block> { secondBlocks[0] }; List<string> ls = new List<string> { secondBlocks[0].Label }; b.TransferCmd = new GotoCmd(Token.NoToken, ls, bs); } List<Block> blocks = Enumerable.Union(firstBlocks, secondBlocks).ToList(); 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>(); requires.Add(DisjointnessRequires(program, first.thatInParams.Union(second.thisInParams), frame)); foreach (AssertCmd assertCmd in Enumerable.Union(first.thatGate, second.thisGate)) requires.Add(new Requires(false, assertCmd.Expr)); var transitionRelationComputation = new TransitionRelationComputation(program, first, second, frame, new HashSet<Variable>()); Expr transitionRelation = transitionRelationComputation.TransitionRelationCompute(); { List<Block> bs = new List<Block> { blocks[0] }; List<string> ls = new List<string> { blocks[0].Label }; var initBlock = new Block(Token.NoToken, string.Format("{0}_{1}_init", first.proc.Name, second.proc.Name), transitionRelationComputation.TriggerAssumes(), new GotoCmd(Token.NoToken, ls, bs)); blocks.Insert(0, initBlock); } IEnumerable<Expr> linearityAssumes = DisjointnessExpr(program, first.thatOutParams.Union(second.thisInParams), frame).Union(DisjointnessExpr(program, first.thatOutParams.Union(second.thisOutParams), frame)); Ensures ensureCheck = new Ensures(false, Expr.Imp(Expr.And(linearityAssumes), transitionRelation)); ensureCheck.ErrorData = string.Format("Commutativity check between {0} and {1} failed", first.proc.Name, second.proc.Name); List<Ensures> ensures = new List<Ensures> { ensureCheck }; string checkerName = string.Format("CommutativityChecker_{0}_{1}", first.proc.Name, second.proc.Name); List<IdentifierExpr> globalVars = civlTypeChecker.SharedVariables.Select(x => Expr.Ident(x)).ToList(); 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); }
public void TypeCheck() { // Pure procedures foreach (var proc in program.Procedures.Where(proc => proc.IsPure())) { if (proc.IsYield()) { Error(proc, "Pure procedure must not yield"); continue; } if (FindLayers(proc.Attributes).Count != 0) { 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(); } // Atomic procedures (not yielding) foreach (var proc in program.Procedures.Where(proc => !proc.IsYield())) { 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; // Implementations of atomic procedures foreach (Implementation impl in program.Implementations) { AtomicProcedureInfo atomicProcedureInfo; if (!procToAtomicProcedureInfo.TryGetValue(impl.Proc, out atomicProcedureInfo)) continue; 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; // Yielding procedures foreach (var proc in program.Procedures.Where(proc => proc.IsYield())) { 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); }
private void CreateFailurePreservationChecker(Program program, AtomicActionInfo first, AtomicActionInfo second) { if (first.gateUsedGlobalVars.Intersect(second.modifiedGlobalVars).Count() == 0) return; if (!failurePreservationCheckerCache.Add(new Tuple<AtomicActionInfo, AtomicActionInfo>(first, second))) return; List<Variable> inputs = Enumerable.Union(first.thatInParams, second.thisInParams).ToList(); List<Variable> outputs = Enumerable.Union(first.thatOutParams, second.thisOutParams).ToList(); List<Variable> locals = new List<Variable>(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 = new List<Requires>(); requires.Add(DisjointnessRequires(program, first.thatInParams.Union(second.thisInParams), frame)); Expr gateExpr = Expr.Not(Expr.And(first.thatGate.Select(a => a.Expr))); gateExpr.Type = Type.Bool; // necessary? requires.Add(new Requires(false, gateExpr)); foreach (AssertCmd assertCmd in second.thisGate) requires.Add(new Requires(false, assertCmd.Expr)); IEnumerable<Expr> linearityAssumes = DisjointnessExpr(program, first.thatInParams.Union(second.thisOutParams), frame); Ensures ensureCheck = new Ensures(false, Expr.Imp(Expr.And(linearityAssumes), gateExpr)); ensureCheck.ErrorData = string.Format("Gate failure of {0} not preserved by {1}", first.proc.Name, second.proc.Name); List<Ensures> ensures = new List<Ensures> { ensureCheck }; string checkerName = string.Format("FailurePreservationChecker_{0}_{1}", first.proc.Name, second.proc.Name); List<IdentifierExpr> globalVars = civlTypeChecker.SharedVariables.Select(x => Expr.Ident(x)).ToList(); 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 CreateCommutativityChecker(Program program, AtomicActionInfo first, AtomicActionInfo second) { if (first == second && first.thatInParams.Count == 0 && first.thatOutParams.Count == 0) { return; } if (first.CommutesWith(second)) { return; } if (!commutativityCheckerCache.Add(new Tuple <AtomicActionInfo, AtomicActionInfo>(first, second))) { return; } List <Variable> inputs = Enumerable.Union(first.thatInParams, second.thisInParams).ToList(); List <Variable> outputs = Enumerable.Union(first.thatOutParams, second.thisOutParams).ToList(); List <Variable> locals = Enumerable.Union(first.thatAction.LocVars, second.thisAction.LocVars).ToList(); List <Block> firstBlocks = CloneBlocks(first.thatAction.Blocks); List <Block> secondBlocks = CloneBlocks(second.thisAction.Blocks); foreach (Block b in firstBlocks.Where(b => b.TransferCmd is ReturnCmd)) { List <Block> bs = new List <Block> { secondBlocks[0] }; List <string> ls = new List <string> { secondBlocks[0].Label }; b.TransferCmd = new GotoCmd(Token.NoToken, ls, bs); } List <Block> blocks = Enumerable.Union(firstBlocks, secondBlocks).ToList(); 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>(); requires.Add(DisjointnessRequires(program, first.thatInParams.Union(second.thisInParams), frame)); foreach (AssertCmd assertCmd in Enumerable.Union(first.thatGate, second.thisGate)) { requires.Add(new Requires(false, assertCmd.Expr)); } var transitionRelationComputation = new TransitionRelationComputation(program, first, second, frame, new HashSet <Variable>()); Expr transitionRelation = transitionRelationComputation.TransitionRelationCompute(); { List <Block> bs = new List <Block> { blocks[0] }; List <string> ls = new List <string> { blocks[0].Label }; var initBlock = new Block(Token.NoToken, string.Format("{0}_{1}_init", first.proc.Name, second.proc.Name), transitionRelationComputation.TriggerAssumes(), new GotoCmd(Token.NoToken, ls, bs)); blocks.Insert(0, initBlock); } var thisInParamsFiltered = second.thisInParams.Where(v => linearTypeChecker.FindLinearKind(v) != LinearKind.LINEAR_IN); IEnumerable <Expr> linearityAssumes = Enumerable.Union( DisjointnessExpr(program, first.thatOutParams.Union(thisInParamsFiltered), frame), DisjointnessExpr(program, first.thatOutParams.Union(second.thisOutParams), frame)); // TODO: add further disjointness expressions? Ensures ensureCheck = new Ensures(false, Expr.Imp(Expr.And(linearityAssumes), transitionRelation)); ensureCheck.ErrorData = string.Format("Commutativity check between {0} and {1} failed", first.proc.Name, second.proc.Name); List <Ensures> ensures = new List <Ensures> { ensureCheck }; string checkerName = string.Format("CommutativityChecker_{0}_{1}", first.proc.Name, second.proc.Name); List <IdentifierExpr> globalVars = civlTypeChecker.SharedVariables.Select(x => Expr.Ident(x)).ToList(); 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 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 = new List<Requires>(); requires.Add(DisjointnessRequires(program, second.thisInParams, 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(); Ensures ensureCheck = new Ensures(false, ensuresExpr); ensureCheck.ErrorData = string.Format("{0} is blocking", second.proc.Name); List<Ensures> ensures = new List<Ensures> { ensureCheck }; List<Block> blocks = new List<Block> { new Block(Token.NoToken, "L", new List<Cmd>(), new ReturnCmd(Token.NoToken)) }; string checkerName = string.Format("NonBlockingChecker_{0}", second.proc.Name); List<IdentifierExpr> globalVars = civlTypeChecker.SharedVariables.Select(x => Expr.Ident(x)).ToList(); 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); }
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; } 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; } 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)) { 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; } procToActionInfo[impl.Proc].hasImplementation = true; } foreach (var proc in procToActionInfo.Keys) { ActionInfo actionInfo = procToActionInfo[proc]; if (actionInfo.isExtern && actionInfo.hasImplementation) { Error(proc, "Extern procedure cannot have an implementation"); continue; } if (actionInfo.isExtern || actionInfo.hasImplementation) { continue; } if (leastUnimplementedLayerNum == int.MaxValue) { leastUnimplementedLayerNum = actionInfo.createdAtLayerNum; } else if (leastUnimplementedLayerNum != actionInfo.createdAtLayerNum) { 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); foreach (Procedure proc in program.Procedures) { if (procToActionInfo.ContainsKey(proc)) { continue; } foreach (var ie in proc.Modifies) { if (!SharedVariables.Contains(ie.Decl)) { continue; } Error(proc, "A ghost procedure must not modify a global variable with layer annotation"); } } if (errorCount > 0) { return; } YieldTypeChecker.PerformYieldSafeCheck(this); new LayerEraser().VisitProgram(program); }
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 = RemoveDuplicatesAndSort(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"); } else if (globalVarToSharedVarInfo[ie.Decl].introLayerNum != procLayerNums[0]) { Error(proc, "The introduction layer of a modified global variable must be identical to the layer of the atomic procedure"); } } if (proc.Modifies.Count == 0 || procLayerNums.Count == 1) { procToAtomicProcedureInfo[proc] = new AtomicProcedureInfo(new HashSet<int>(procLayerNums)); } else { Error(proc, "An atomic procedure with more than one layer must not modify a global variable"); } } 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 = new LayerRange(atomicProcedureInfo.layers); 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 (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(QKeyValue.FindBoolAttribute(node.Attributes, "ghost"), layer); } for (int i = 0; i < node.Proc.InParams.Count; i++) { Variable v = node.Proc.InParams[i]; var layer = FindLocalVariableLayer(node.Proc, v, procToActionInfo[node.Proc].createdAtLayerNum); if (layer == int.MinValue) continue; localVarToLocalVariableInfo[v] = new LocalVariableInfo(false, layer); localVarToLocalVariableInfo[node.InParams[i]] = new LocalVariableInfo(false, layer); } for (int i = 0; i < node.Proc.OutParams.Count; i++) { Variable v = node.Proc.OutParams[i]; var layer = FindLocalVariableLayer(node.Proc, v, procToActionInfo[node.Proc].createdAtLayerNum); if (layer == int.MinValue) continue; localVarToLocalVariableInfo[v] = new LocalVariableInfo(false, layer); localVarToLocalVariableInfo[node.OutParams[i]] = new LocalVariableInfo(false, layer); } } 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"); } } 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); }