/// <summary> /// The abstract transition relation. /// 'cmd' is allowed to be a StateCmd. /// </summary> static NativeLattice.Element Step(NativeLattice lattice, Cmd cmd, NativeLattice.Element elmt) { Contract.Requires(lattice != null); Contract.Requires(cmd != null); Contract.Requires(elmt != null); Contract.Ensures(Contract.Result <NativeLattice.Element>() != null); if (cmd is AssignCmd) { // parallel assignment var c = (AssignCmd)cmd; elmt = lattice.Update(elmt, c.AsSimpleAssignCmd); } else if (cmd is HavocCmd) { var c = (HavocCmd)cmd; foreach (IdentifierExpr id in c.Vars) { Contract.Assert(id != null); elmt = lattice.Eliminate(elmt, id.Decl); } } else if (cmd is PredicateCmd) { var c = (PredicateCmd)cmd; var conjuncts = new List <Expr>(); foreach (var ee in Conjuncts(c.Expr)) { Contract.Assert(ee != null); elmt = lattice.Constrain(elmt, ee); } } else if (cmd is StateCmd) { var c = (StateCmd)cmd; // Iterate the abstract transition on all the commands in the desugaring of the call foreach (Cmd callDesug in c.Cmds) { Contract.Assert(callDesug != null); elmt = Step(lattice, callDesug, elmt); } // Project out the local variables of the StateCmd foreach (Variable local in c.Locals) { Contract.Assert(local != null); elmt = lattice.Eliminate(elmt, local); } } else if (cmd is SugaredCmd) { var c = (SugaredCmd)cmd; elmt = Step(lattice, c.Desugaring, elmt); } else if (cmd is CommentCmd) { // skip } else { Contract.Assert(false); // unknown command } return(elmt); }
public static void Analyze(Implementation impl, NativeLattice lattice, NativeLattice.Element start) { // We need to keep track of some information for each(some) block(s). To do that efficiently, // we number the implementation's blocks sequentially, and then we can use arrays to store // the additional information. var pre = new NativeLattice.Element[impl.Blocks.Count]; // set to null if we never compute a join/widen at this block var post = CommandLineOptions.Clo.InstrumentInfer == CommandLineOptions.InstrumentationPlaces.Everywhere ? new NativeLattice.Element[impl.Blocks.Count] : null; var iterations = new int[impl.Blocks.Count]; var bottom = lattice.Bottom; int n = 0; foreach (var block in impl.Blocks) { block.aiId = n; // Note: The forward analysis below will store lattice elements in pre[n] if pre[n] is non-null. // Thus, the assignment "pre[n] = bottom;" below must be done under the following condition: // n == 0 || block.widenBlock // One possible strategy would be to do it only under that condition. Alternatively, // one could do the assignment under the following condition: // n == 0 || block.widenBlock || block.Predecessors.Length != 1 // (which would require first setting the Predecessors field). In any case, if // CommandLineOptions.Clo.InstrumentInfer == CommandLineOptions.InstrumentationPlaces.Everywhere // then all pre[n] should be set. pre[n] = bottom; n++; } Contract.Assert(n == impl.Blocks.Count); var workItems = new Queue<Tuple<Block, NativeLattice.Element>>(); workItems.Enqueue(new Tuple<Block, NativeLattice.Element>(impl.Blocks[0], start)); //ComputeBlockInvariantsNative(impl, ); // compute a fixpoint here while (workItems.Count > 0) { var workItem = workItems.Dequeue(); var b = workItem.Item1; var id = b.aiId; var e = workItem.Item2; if (pre[id] == null) { // no pre information stored here, so just go ahead through the block } else if (lattice.Below(e, pre[id])) { // no change continue; } else if (b.widenBlock && CommandLineOptions.Clo.StepsBeforeWidening <= iterations[id]) { e = lattice.Widen(pre[id], e); pre[id] = e; iterations[id]++; } else { e = lattice.Join(pre[id], e); pre[id] = e; iterations[id]++; } // propagate'e' through b.Cmds foreach (Cmd cmd in b.Cmds) { e = Step(lattice, cmd, e); } if (post != null && pre[id] != null) { post[id] = e; } var g = b.TransferCmd as GotoCmd; if (g != null) { // if g==null, it's a pity we didn't pay attention to that earlier, because then we could have skipped analyzing the code in this block foreach (Block succ in g.labelTargets) { workItems.Enqueue(new Tuple<Block, NativeLattice.Element>(succ, e)); } } } Instrument(impl, pre, post); }
public static void Analyze(Implementation impl, NativeLattice lattice, NativeLattice.Element start) { // We need to keep track of some information for each(some) block(s). To do that efficiently, // we number the implementation's blocks sequentially, and then we can use arrays to store // the additional information. var pre = new NativeLattice.Element[impl.Blocks .Count]; // set to null if we never compute a join/widen at this block var post = CommandLineOptions.Clo.InstrumentInfer == CommandLineOptions.InstrumentationPlaces.Everywhere ? new NativeLattice.Element[impl.Blocks.Count] : null; var iterations = new int[impl.Blocks.Count]; var bottom = lattice.Bottom; int n = 0; foreach (var block in impl.Blocks) { block.aiId = n; // Note: The forward analysis below will store lattice elements in pre[n] if pre[n] is non-null. // Thus, the assignment "pre[n] = bottom;" below must be done under the following condition: // n == 0 || block.widenBlock // One possible strategy would be to do it only under that condition. Alternatively, // one could do the assignment under the following condition: // n == 0 || block.widenBlock || block.Predecessors.Length != 1 // (which would require first setting the Predecessors field). In any case, if // CommandLineOptions.Clo.InstrumentInfer == CommandLineOptions.InstrumentationPlaces.Everywhere // then all pre[n] should be set. pre[n] = bottom; n++; } Contract.Assert(n == impl.Blocks.Count); var workItems = new Queue <Tuple <Block, NativeLattice.Element> >(); workItems.Enqueue(new Tuple <Block, NativeLattice.Element>(impl.Blocks[0], start)); //ComputeBlockInvariantsNative(impl, ); // compute a fixpoint here while (workItems.Count > 0) { var workItem = workItems.Dequeue(); var b = workItem.Item1; var id = b.aiId; var e = workItem.Item2; if (pre[id] == null) { // no pre information stored here, so just go ahead through the block } else if (lattice.Below(e, pre[id])) { // no change continue; } else if (b.widenBlock && CommandLineOptions.Clo.Ai.StepsBeforeWidening <= iterations[id]) { e = lattice.Widen(pre[id], e); pre[id] = e; iterations[id]++; } else { e = lattice.Join(pre[id], e); pre[id] = e; iterations[id]++; } // propagate'e' through b.Cmds foreach (Cmd cmd in b.Cmds) { e = Step(lattice, cmd, e); } if (post != null && pre[id] != null) { post[id] = e; } var g = b.TransferCmd as GotoCmd; if (g != null) { // if g==null, it's a pity we didn't pay attention to that earlier, because then we could have skipped analyzing the code in this block foreach (Block succ in g.labelTargets) { workItems.Enqueue(new Tuple <Block, NativeLattice.Element>(succ, e)); } } } Instrument(impl, pre, post); }