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 void TypeCheck() { foreach (Declaration decl in program.TopLevelDeclarations) { Procedure proc = decl as Procedure; if (proc == null) { continue; } foreach (Ensures e in proc.Ensures) { int phaseNum; MoverType moverType = MoverCheck.GetMoverType(e, out phaseNum); 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; } procToActionInfo[proc] = new ActionInfo(proc, codeExpr, moverType, phaseNum); } } this.VisitProgram(program); #if QED YieldTypeChecker.PerformYieldTypeChecking(this); #endif }
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 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); }
private void CreateGatePreservationChecker(Program program, ActionInfo first, ActionInfo second) { Tuple <ActionInfo, ActionInfo> actionPair = new Tuple <ActionInfo, ActionInfo>(first, second); if (gatePreservationCheckerCache.Contains(actionPair)) { return; } gatePreservationCheckerCache.Add(actionPair); List <Variable> inputs = new List <Variable>(); inputs.AddRange(first.thisInParams); inputs.AddRange(second.thatInParams); List <Variable> outputs = new List <Variable>(); outputs.AddRange(first.thisOutParams); outputs.AddRange(second.thatOutParams); List <Variable> locals = new List <Variable>(); locals.AddRange(second.thatAction.LocVars); List <Block> secondBlocks = CloneBlocks(second.thatAction.Blocks); List <Requires> requires = DisjointnessRequires(program, first, second); List <Ensures> ensures = new List <Ensures>(); foreach (AssertCmd assertCmd in first.thisGate) { requires.Add(new Requires(false, assertCmd.Expr)); ensures.Add(new Ensures(false, assertCmd.Expr)); } string checkerName = string.Format("GatePreservationChecker_{0}_{1}", first.proc.Name, second.proc.Name); List <IdentifierExpr> globalVars = new List <IdentifierExpr>(); program.GlobalVariables().Iter(x => globalVars.Add(new IdentifierExpr(Token.NoToken, 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, ActionInfo first, ActionInfo second) { Tuple <ActionInfo, ActionInfo> actionPair = new Tuple <ActionInfo, ActionInfo>(first, second); if (failurePreservationCheckerCache.Contains(actionPair)) { return; } failurePreservationCheckerCache.Add(actionPair); List <Variable> inputs = new List <Variable>(); inputs.AddRange(first.thisInParams); inputs.AddRange(second.thatInParams); Expr transitionRelation = (new TransitionRelationComputation(program, second)).Compute(); Expr expr = Expr.True; foreach (AssertCmd assertCmd in first.thisGate) { expr = Expr.And(assertCmd.Expr, expr); } List <Requires> requires = DisjointnessRequires(program, first, second); requires.Add(new Requires(false, Expr.Not(expr))); foreach (AssertCmd assertCmd in second.thatGate) { requires.Add(new Requires(false, assertCmd.Expr)); } Dictionary <Variable, Expr> map = new Dictionary <Variable, Expr>(); Dictionary <Variable, Expr> oldMap = new Dictionary <Variable, Expr>(); List <Variable> boundVars = new List <Variable>(); foreach (Variable v in program.GlobalVariables()) { BoundVariable bv = new BoundVariable(Token.NoToken, new TypedIdent(Token.NoToken, "post_" + v.Name, v.TypedIdent.Type)); boundVars.Add(bv); map[v] = new IdentifierExpr(Token.NoToken, bv); } foreach (Variable v in second.thatOutParams) { { BoundVariable bv = new BoundVariable(Token.NoToken, new TypedIdent(Token.NoToken, "post_" + v.Name, v.TypedIdent.Type)); boundVars.Add(bv); map[v] = new IdentifierExpr(Token.NoToken, bv); } { BoundVariable bv = new BoundVariable(Token.NoToken, new TypedIdent(Token.NoToken, "pre_" + v.Name, v.TypedIdent.Type)); boundVars.Add(bv); oldMap[v] = new IdentifierExpr(Token.NoToken, bv); } } foreach (Variable v in second.thatAction.LocVars) { BoundVariable bv = new BoundVariable(Token.NoToken, new TypedIdent(Token.NoToken, "pre_" + v.Name, v.TypedIdent.Type)); boundVars.Add(bv); oldMap[v] = new IdentifierExpr(Token.NoToken, bv); } Expr ensuresExpr = Expr.And(transitionRelation, Expr.Not(expr)); if (boundVars.Count > 0) { Substitution subst = Substituter.SubstitutionFromHashtable(map); Substitution oldSubst = Substituter.SubstitutionFromHashtable(oldMap); ensuresExpr = new ExistsExpr(Token.NoToken, boundVars, (Expr) new MySubstituter(subst, oldSubst).Visit(ensuresExpr)); } List <Ensures> ensures = new List <Ensures>(); ensures.Add(new Ensures(false, ensuresExpr)); List <Block> blocks = new List <Block>(); blocks.Add(new Block(Token.NoToken, "L", new List <Cmd>(), new ReturnCmd(Token.NoToken))); string checkerName = string.Format("FailurePreservationChecker_{0}_{1}", first.proc.Name, second.proc.Name); List <IdentifierExpr> globalVars = new List <IdentifierExpr>(); program.GlobalVariables().Iter(x => globalVars.Add(new IdentifierExpr(Token.NoToken, 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); }
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); }
private List <Requires> DisjointnessRequires(Program program, ActionInfo first, ActionInfo second) { 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 program.GlobalVariables()) { var domainName = linearTypeChecker.FindDomainName(v); if (domainName == null) { continue; } domainNameToScope[domainName].Add(v); } foreach (Variable v in first.thisInParams) { var domainName = linearTypeChecker.FindDomainName(v); if (domainName == null) { continue; } domainNameToScope[domainName].Add(v); } for (int i = 0; i < second.thatInParams.Count; i++) { var domainName = linearTypeChecker.FindDomainName(second.thisInParams[i]); if (domainName == null) { continue; } domainNameToScope[domainName].Add(second.thatInParams[i]); } foreach (string domainName in domainNameToScope.Keys) { requires.Add(new Requires(false, linearTypeChecker.DisjointnessExpr(domainName, domainNameToScope[domainName]))); } return(requires); }
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 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 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 CreateCommutativityChecker(Program program, ActionInfo first, ActionInfo second) { Tuple<ActionInfo, ActionInfo> actionPair = new Tuple<ActionInfo, ActionInfo>(first, second); if (commutativityCheckerCache.Contains(actionPair)) return; commutativityCheckerCache.Add(actionPair); List<Variable> inputs = new List<Variable>(); inputs.AddRange(first.thisInParams); inputs.AddRange(second.thatInParams); List<Variable> outputs = new List<Variable>(); outputs.AddRange(first.thisOutParams); outputs.AddRange(second.thatOutParams); List<Variable> locals = new List<Variable>(); locals.AddRange(first.thisAction.LocVars); locals.AddRange(second.thatAction.LocVars); List<Block> firstBlocks = CloneBlocks(first.thisAction.Blocks); List<Block> secondBlocks = CloneBlocks(second.thatAction.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); List<Requires> requires = DisjointnessRequires(program, first, second); List<Ensures> ensures = new List<Ensures>(); Expr transitionRelation = (new TransitionRelationComputation(program, first, second)).Compute(); ensures.Add(new Ensures(false, transitionRelation)); string checkerName = string.Format("CommutativityChecker_{0}_{1}", first.proc.Name, second.proc.Name); List<IdentifierExpr> globalVars = new List<IdentifierExpr>(); program.GlobalVariables().Iter(x => globalVars.Add(new IdentifierExpr(Token.NoToken, 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); }
public void TypeCheck() { foreach (Declaration decl in program.TopLevelDeclarations) { Procedure proc = decl as Procedure; if (proc == null) continue; foreach (Ensures e in proc.Ensures) { int phaseNum; MoverType moverType = MoverCheck.GetMoverType(e, out phaseNum); 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; } procToActionInfo[proc] = new ActionInfo(proc, codeExpr, moverType, phaseNum); } } this.VisitProgram(program); #if QED YieldTypeChecker.PerformYieldTypeChecking(this); #endif }
public TransitionRelationComputation(Program program, ActionInfo first, ActionInfo second) { this.program = program; this.first = first; this.second = second; this.dfsStack = new Stack<Block>(); this.transitionRelation = Expr.False; this.boundVariableCount = 0; }
private List<Requires> DisjointnessRequires(Program program, ActionInfo first, ActionInfo second) { 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 program.GlobalVariables()) { var domainName = linearTypeChecker.FindDomainName(v); if (domainName == null) continue; domainNameToScope[domainName].Add(v); } foreach (Variable v in first.thisInParams) { var domainName = linearTypeChecker.FindDomainName(v); if (domainName == null) continue; domainNameToScope[domainName].Add(v); } for (int i = 0; i < second.thatInParams.Count; i++) { var domainName = linearTypeChecker.FindDomainName(second.thisInParams[i]); if (domainName == null) continue; domainNameToScope[domainName].Add(second.thatInParams[i]); } foreach (string domainName in domainNameToScope.Keys) { requires.Add(new Requires(false, linearTypeChecker.DisjointnessExpr(domainName, domainNameToScope[domainName]))); } return requires; }
private void CreateGatePreservationChecker(Program program, ActionInfo first, ActionInfo second) { Tuple<ActionInfo, ActionInfo> actionPair = new Tuple<ActionInfo, ActionInfo>(first, second); if (gatePreservationCheckerCache.Contains(actionPair)) return; gatePreservationCheckerCache.Add(actionPair); List<Variable> inputs = new List<Variable>(); inputs.AddRange(first.thisInParams); inputs.AddRange(second.thatInParams); List<Variable> outputs = new List<Variable>(); outputs.AddRange(first.thisOutParams); outputs.AddRange(second.thatOutParams); List<Variable> locals = new List<Variable>(); locals.AddRange(second.thatAction.LocVars); List<Block> secondBlocks = CloneBlocks(second.thatAction.Blocks); List<Requires> requires = DisjointnessRequires(program, first, second); List<Ensures> ensures = new List<Ensures>(); foreach (AssertCmd assertCmd in first.thisGate) { requires.Add(new Requires(false, assertCmd.Expr)); ensures.Add(new Ensures(false, assertCmd.Expr)); } string checkerName = string.Format("GatePreservationChecker_{0}_{1}", first.proc.Name, second.proc.Name); List<IdentifierExpr> globalVars = new List<IdentifierExpr>(); program.GlobalVariables().Iter(x => globalVars.Add(new IdentifierExpr(Token.NoToken, 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, ActionInfo first, ActionInfo second) { Tuple<ActionInfo, ActionInfo> actionPair = new Tuple<ActionInfo, ActionInfo>(first, second); if (failurePreservationCheckerCache.Contains(actionPair)) return; failurePreservationCheckerCache.Add(actionPair); List<Variable> inputs = new List<Variable>(); inputs.AddRange(first.thisInParams); inputs.AddRange(second.thatInParams); Expr transitionRelation = (new TransitionRelationComputation(program, second)).Compute(); Expr expr = Expr.True; foreach (AssertCmd assertCmd in first.thisGate) { expr = Expr.And(assertCmd.Expr, expr); } List<Requires> requires = DisjointnessRequires(program, first, second); requires.Add(new Requires(false, Expr.Not(expr))); foreach (AssertCmd assertCmd in second.thatGate) { requires.Add(new Requires(false, assertCmd.Expr)); } Dictionary<Variable, Expr> map = new Dictionary<Variable, Expr>(); Dictionary<Variable, Expr> oldMap = new Dictionary<Variable, Expr>(); List<Variable> boundVars = new List<Variable>(); foreach (Variable v in program.GlobalVariables()) { BoundVariable bv = new BoundVariable(Token.NoToken, new TypedIdent(Token.NoToken, "post_" + v.Name, v.TypedIdent.Type)); boundVars.Add(bv); map[v] = new IdentifierExpr(Token.NoToken, bv); } foreach (Variable v in second.thatOutParams) { { BoundVariable bv = new BoundVariable(Token.NoToken, new TypedIdent(Token.NoToken, "post_" + v.Name, v.TypedIdent.Type)); boundVars.Add(bv); map[v] = new IdentifierExpr(Token.NoToken, bv); } { BoundVariable bv = new BoundVariable(Token.NoToken, new TypedIdent(Token.NoToken, "pre_" + v.Name, v.TypedIdent.Type)); boundVars.Add(bv); oldMap[v] = new IdentifierExpr(Token.NoToken, bv); } } foreach (Variable v in second.thatAction.LocVars) { BoundVariable bv = new BoundVariable(Token.NoToken, new TypedIdent(Token.NoToken, "pre_" + v.Name, v.TypedIdent.Type)); boundVars.Add(bv); oldMap[v] = new IdentifierExpr(Token.NoToken, bv); } Expr ensuresExpr = Expr.And(transitionRelation, Expr.Not(expr)); if (boundVars.Count > 0) { Substitution subst = Substituter.SubstitutionFromHashtable(map); Substitution oldSubst = Substituter.SubstitutionFromHashtable(oldMap); ensuresExpr = new ExistsExpr(Token.NoToken, boundVars, (Expr)new MySubstituter(subst, oldSubst).Visit(ensuresExpr)); } List<Ensures> ensures = new List<Ensures>(); ensures.Add(new Ensures(false, ensuresExpr)); List<Block> blocks = new List<Block>(); blocks.Add(new Block(Token.NoToken, "L", new List<Cmd>(), new ReturnCmd(Token.NoToken))); string checkerName = string.Format("FailurePreservationChecker_{0}_{1}", first.proc.Name, second.proc.Name); List<IdentifierExpr> globalVars = new List<IdentifierExpr>(); program.GlobalVariables().Iter(x => globalVars.Add(new IdentifierExpr(Token.NoToken, 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); }
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 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); }