Example #1
0
 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;
 }
Example #2
0
        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);
        }
Example #3
0
        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);
        }
Example #4
0
 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);
 }
Example #5
0
        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);
        }
Example #6
0
            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);
            }
Example #7
0
        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();
        }
Example #10
0
        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);
        }
Example #11
0
        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);
        }
Example #12
0
 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)
 {
 }
Example #14
0
 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);
 }
Example #15
0
        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);
        }
Example #16
0
 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;
 }
Example #17
0
 public TransitionRelationComputation(Program program, AtomicActionInfo first, AtomicActionInfo second, HashSet<Variable> frame, HashSet<Variable> postExistVars)
 {
     this.postExistVars = postExistVars;
     this.frame = frame;
     TransitionRelationComputationHelper(program, first, second);
 }
Example #18
0
        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);
        }
Example #19
0
        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) { }
Example #21
0
        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);
        }
Example #22
0
        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);
                }
            }
        }
Example #23
0
        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);
        }
Example #24
0
        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);
        }
Example #25
0
        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);
        }
Example #26
0
        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);
        }
Example #27
0
        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);
        }
Example #28
0
        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);
        }
Example #29
0
        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);
        }
Example #30
0
        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);
        }
Example #31
0
        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);
        }