private Graph<Block> ComputeYieldingLoopHeaders(Implementation impl, out HashSet<Block> yieldingHeaders) { Graph<Block> graph; impl.PruneUnreachableBlocks(); impl.ComputePredecessorsForBlocks(); graph = Program.GraphFromImpl(impl); graph.ComputeLoops(); if (!graph.Reducible) { throw new Exception("Irreducible flow graphs are unsupported."); } yieldingHeaders = new HashSet<Block>(); IEnumerable<Block> sortedHeaders = graph.SortHeadersByDominance(); foreach (Block header in sortedHeaders) { if (yieldingHeaders.Any(x => graph.DominatorMap.DominatedBy(x, header))) { yieldingHeaders.Add(header); } else if (IsYieldingHeader(graph, header)) { yieldingHeaders.Add(header); } else { continue; } } return graph; }
public override Implementation VisitImplementation(Implementation node) { node.PruneUnreachableBlocks(); node.ComputePredecessorsForBlocks(); GraphUtil.Graph<Block> graph = Program.GraphFromImpl(node); graph.ComputeLoops(); HashSet<Variable> start = new HashSet<Variable>(globalVarToDomainName.Keys); for (int i = 0; i < node.InParams.Count; i++) { Variable v = node.Proc.InParams[i]; string domainName = FindDomainName(v); if (domainName != null) { var kind = FindLinearKind(v); inParamToLinearQualifier[node.InParams[i]] = new LinearQualifier(domainName, kind); if (kind == LinearKind.LINEAR || kind == LinearKind.LINEAR_IN) { start.Add(node.InParams[i]); } } } for (int i = 0; i < node.OutParams.Count; i++) { string domainName = FindDomainName(node.Proc.OutParams[i]); if (domainName != null) { outParamToDomainName[node.OutParams[i]] = domainName; } } var oldErrorCount = this.errorCount; var impl = base.VisitImplementation(node); if (oldErrorCount < this.errorCount) return impl; Stack<Block> dfsStack = new Stack<Block>(); HashSet<Block> dfsStackAsSet = new HashSet<Block>(); availableLinearVars[node.Blocks[0]] = start; dfsStack.Push(node.Blocks[0]); dfsStackAsSet.Add(node.Blocks[0]); while (dfsStack.Count > 0) { Block b = dfsStack.Pop(); dfsStackAsSet.Remove(b); HashSet<Variable> end = PropagateAvailableLinearVarsAcrossBlock(b); if (b.TransferCmd is ReturnCmd) { foreach (GlobalVariable g in globalVarToDomainName.Keys.Except(end)) { Error(b.TransferCmd, string.Format("Global variable {0} must be available at a return", g.Name)); } foreach (Variable v in node.InParams) { if (FindDomainName(v) == null || FindLinearKind(v) == LinearKind.LINEAR_IN || end.Contains(v)) continue; Error(b.TransferCmd, string.Format("Input variable {0} must be available at a return", v.Name)); } foreach (Variable v in node.OutParams) { if (FindDomainName(v) == null || end.Contains(v)) continue; Error(b.TransferCmd, string.Format("Output variable {0} must be available at a return", v.Name)); } continue; } GotoCmd gotoCmd = b.TransferCmd as GotoCmd; foreach (Block target in gotoCmd.labelTargets) { if (!availableLinearVars.ContainsKey(target)) { availableLinearVars[target] = new HashSet<Variable>(end); dfsStack.Push(target); dfsStackAsSet.Add(target); } else { var savedAvailableVars = new HashSet<Variable>(availableLinearVars[target]); availableLinearVars[target].IntersectWith(end); if (savedAvailableVars.IsProperSupersetOf(availableLinearVars[target]) && !dfsStackAsSet.Contains(target)) { dfsStack.Push(target); dfsStackAsSet.Add(target); } } } } if (graph.Reducible) { foreach (Block header in graph.Headers) { foreach (GlobalVariable g in globalVarToDomainName.Keys.Except(availableLinearVars[header])) { Error(header, string.Format("Global variable {0} must be available at a loop head", g.Name)); } } } return impl; }
public Graph<Block> ProcessLoops(Implementation impl) { while (true) { impl.PruneUnreachableBlocks(); impl.ComputePredecessorsForBlocks(); Graph<Block/*!*/>/*!*/ g = GraphFromImpl(impl); g.ComputeLoops(); if (g.Reducible) { return g; } throw new IrreducibleLoopException(); #if USED_CODE System.Diagnostics.Debug.Assert(g.SplitCandidates.Count > 0); Block splitCandidate = null; foreach (Block b in g.SplitCandidates) { if (b.Predecessors.Length > 1) { splitCandidate = b; break; } } System.Diagnostics.Debug.Assert(splitCandidate != null); int count = 0; foreach (Block b in splitCandidate.Predecessors) { GotoCmd gotoCmd = (GotoCmd)b.TransferCmd; gotoCmd.labelNames.Remove(splitCandidate.Label); gotoCmd.labelTargets.Remove(splitCandidate); CodeCopier codeCopier = new CodeCopier(new Hashtable(), new Hashtable()); List<Cmd> newCmdSeq = codeCopier.CopyCmdSeq(splitCandidate.Cmds); TransferCmd newTransferCmd; GotoCmd splitGotoCmd = splitCandidate.TransferCmd as GotoCmd; if (splitGotoCmd == null) { newTransferCmd = new ReturnCmd(splitCandidate.tok); } else { List<String> newLabelNames = new List<String>(); newLabelNames.AddRange(splitGotoCmd.labelNames); List<Block> newLabelTargets = new List<Block>(); newLabelTargets.AddRange(splitGotoCmd.labelTargets); newTransferCmd = new GotoCmd(splitCandidate.tok, newLabelNames, newLabelTargets); } Block copy = new Block(splitCandidate.tok, splitCandidate.Label + count++, newCmdSeq, newTransferCmd); impl.Blocks.Add(copy); gotoCmd.AddTarget(copy); } #endif } }
private void Transform4DoomedCheck(Implementation impl) { variable2SequenceNumber = new Dictionary<Variable, int>(); incarnationOriginMap = new Dictionary<Incarnation, Absy>(); if (impl.Blocks.Count < 1) return; impl.PruneUnreachableBlocks(); AddBlocksBetween(impl.Blocks); ResetPredecessors(impl.Blocks); GraphAnalyzer ga = new GraphAnalyzer(impl.Blocks); LoopRemover lr = new LoopRemover(ga); lr.AbstractLoopUnrolling(); impl.Blocks = ga.ToImplementation(out m_UncheckableBlocks); ResetPredecessors(impl.Blocks); // Check for the "BlocksBetween" if all their successors are in m_UncheckableBlocks List<Block> oldblocks = new List<Block>(); oldblocks.AddRange(impl.Blocks); GenerateHelperBlocks(impl); #region Check for the "BlocksBetween" if all their successors are in m_UncheckableBlocks foreach (Block b in impl.Blocks) { if (oldblocks.Contains(b)) continue; GotoCmd gc = b.TransferCmd as GotoCmd; if (gc != null) { bool allsuccUncheckable = true; foreach (Block _b in gc.labelTargets) { if (!m_UncheckableBlocks.Contains(_b)) { allsuccUncheckable = false; break; } } if (allsuccUncheckable && !m_UncheckableBlocks.Contains(b)) m_UncheckableBlocks.Add(b); } } #endregion impl.Blocks = DeepCopyBlocks(impl.Blocks, m_UncheckableBlocks); m_BlockReachabilityMap = new Dictionary<Block, Variable>(); List<Cmd> cs = GenerateReachabilityPredicates(impl); //foreach (Block test in getTheFFinalBlock(impl.Blocks[0])) //{ // test.Cmds.AddRange(cs); //} ResetPredecessors(impl.Blocks); //EmitImpl(impl,false); Dictionary<Variable, Expr> var2Expr = PassifyProgram(impl, new ModelViewInfo(program, impl)); // Collect the last incarnation of each reachability variable in the passive program foreach (KeyValuePair<Block, Variable> kvp in m_BlockReachabilityMap) { if (var2Expr.ContainsKey(kvp.Value)) { m_LastReachVarIncarnation[kvp.Value] = (Expr)var2Expr[kvp.Value]; } } }
private void TransformImpl(Implementation impl) { if (!QKeyValue.FindBoolAttribute(impl.Proc.Attributes, "yields")) return; // Find the yielding loop headers impl.PruneUnreachableBlocks(); impl.ComputePredecessorsForBlocks(); GraphUtil.Graph<Block> graph = Program.GraphFromImpl(impl); graph.ComputeLoops(); if (!graph.Reducible) { throw new Exception("Irreducible flow graphs are unsupported."); } HashSet<Block> yieldingHeaders = new HashSet<Block>(); IEnumerable<Block> sortedHeaders = graph.SortHeadersByDominance(); foreach (Block header in sortedHeaders) { if (yieldingHeaders.Any(x => graph.DominatorMap.DominatedBy(x, header))) { yieldingHeaders.Add(header); } else if (IsYieldingHeader(graph, header)) { yieldingHeaders.Add(header); } else { continue; } } Program program = linearTypeChecker.program; Dictionary<Variable, Expr> map = new Dictionary<Variable, Expr>(); foreach (Variable local in impl.LocVars) { var copy = new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken, local.Name, local.TypedIdent.Type)); map[local] = new IdentifierExpr(Token.NoToken, copy); } Dictionary<Variable, Variable> ogOldGlobalMap = new Dictionary<Variable, Variable>(); foreach (IdentifierExpr ie in globalMods) { Variable g = ie.Decl; LocalVariable l = new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken, string.Format("og_global_old_{0}", g.Name), g.TypedIdent.Type)); ogOldGlobalMap[g] = l; impl.LocVars.Add(l); } Dictionary<string, Variable> domainNameToInputVar = new Dictionary<string, Variable>(); Dictionary<string, Variable> domainNameToLocalVar = new Dictionary<string, Variable>(); { int i = impl.InParams.Count - linearTypeChecker.linearDomains.Count; foreach (string domainName in linearTypeChecker.linearDomains.Keys) { Variable inParam = impl.InParams[i]; domainNameToInputVar[domainName] = inParam; Variable l = new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken, inParam.Name + "_local", inParam.TypedIdent.Type)); domainNameToLocalVar[domainName] = l; impl.LocVars.Add(l); i++; } } // Collect the yield predicates and desugar yields List<List<Cmd>> yields = new List<List<Cmd>>(); List<Cmd> cmds = new List<Cmd>(); foreach (Block b in impl.Blocks) { YieldCmd yieldCmd = null; List<Cmd> newCmds = new List<Cmd>(); for (int i = 0; i < b.Cmds.Count; i++) { Cmd cmd = b.Cmds[i]; if (cmd is YieldCmd) { yieldCmd = (YieldCmd)cmd; continue; } if (yieldCmd != null) { PredicateCmd pcmd = cmd as PredicateCmd; if (pcmd == null) { DesugarYield(yieldCmd, cmds, newCmds, ogOldGlobalMap, domainNameToInputVar, domainNameToLocalVar); if (cmds.Count > 0) { yields.Add(cmds); cmds = new List<Cmd>(); } yieldCmd = null; } else { cmds.Add(pcmd); } } if (cmd is CallCmd) { CallCmd callCmd = cmd as CallCmd; if (callCmd.IsAsync || QKeyValue.FindBoolAttribute(callCmd.Proc.Attributes, "yields")) { AddCallToYieldProc(newCmds, ogOldGlobalMap, domainNameToLocalVar); } if (callCmd.IsAsync) { if (!asyncAndParallelCallDesugarings.ContainsKey(callCmd.Proc.Name)) { asyncAndParallelCallDesugarings[callCmd.Proc.Name] = new Procedure(Token.NoToken, string.Format("DummyAsyncTarget_{0}", callCmd.Proc.Name), callCmd.Proc.TypeParameters, callCmd.Proc.InParams, callCmd.Proc.OutParams, callCmd.Proc.Requires, new List<IdentifierExpr>(), new List<Ensures>()); } var dummyAsyncTargetProc = asyncAndParallelCallDesugarings[callCmd.Proc.Name]; CallCmd dummyCallCmd = new CallCmd(Token.NoToken, dummyAsyncTargetProc.Name, callCmd.Ins, callCmd.Outs); dummyCallCmd.Proc = dummyAsyncTargetProc; newCmds.Add(dummyCallCmd); } else { newCmds.Add(callCmd); } if (callCmd.IsAsync || QKeyValue.FindBoolAttribute(callCmd.Proc.Attributes, "yields")) { HashSet<Variable> availableLinearVars = new HashSet<Variable>(AvailableLinearVars(callCmd)); foreach (IdentifierExpr ie in callCmd.Outs) { if (linearTypeChecker.FindDomainName(ie.Decl) == null) continue; availableLinearVars.Add(ie.Decl); } Dictionary<string, Expr> domainNameToExpr = ComputeAvailableExprs(availableLinearVars, domainNameToInputVar); AddUpdatesToOldGlobalVars(newCmds, ogOldGlobalMap, domainNameToLocalVar, domainNameToExpr); } } else if (cmd is ParCallCmd) { ParCallCmd parCallCmd = cmd as ParCallCmd; AddCallToYieldProc(newCmds, ogOldGlobalMap, domainNameToLocalVar); DesugarParallelCallCmd(newCmds, parCallCmd); HashSet<Variable> availableLinearVars = new HashSet<Variable>(AvailableLinearVars(parCallCmd)); foreach (CallCmd callCmd in parCallCmd.CallCmds) { foreach (IdentifierExpr ie in callCmd.Outs) { if (linearTypeChecker.FindDomainName(ie.Decl) == null) continue; availableLinearVars.Add(ie.Decl); } } Dictionary<string, Expr> domainNameToExpr = ComputeAvailableExprs(availableLinearVars, domainNameToInputVar); AddUpdatesToOldGlobalVars(newCmds, ogOldGlobalMap, domainNameToLocalVar, domainNameToExpr); } else { newCmds.Add(cmd); } } if (yieldCmd != null) { DesugarYield(yieldCmd, cmds, newCmds, ogOldGlobalMap, domainNameToInputVar, domainNameToLocalVar); if (cmds.Count > 0) { yields.Add(cmds); cmds = new List<Cmd>(); } } if (b.TransferCmd is ReturnCmd && QKeyValue.FindBoolAttribute(impl.Proc.Attributes, "yields")) { AddCallToYieldProc(newCmds, ogOldGlobalMap, domainNameToLocalVar); } b.Cmds = newCmds; } foreach (Block header in yieldingHeaders) { Dictionary<string, Expr> domainNameToExpr = ComputeAvailableExprs(AvailableLinearVars(header), domainNameToInputVar); foreach (Block pred in header.Predecessors) { AddCallToYieldProc(pred.Cmds, ogOldGlobalMap, domainNameToLocalVar); AddUpdatesToOldGlobalVars(pred.Cmds, ogOldGlobalMap, domainNameToLocalVar, domainNameToExpr); } List<Cmd> newCmds = new List<Cmd>(); foreach (string domainName in linearTypeChecker.linearDomains.Keys) { newCmds.Add(new AssumeCmd(Token.NoToken, Expr.Binary(BinaryOperator.Opcode.Eq, Expr.Ident(domainNameToLocalVar[domainName]), domainNameToExpr[domainName]))); } foreach (Variable v in ogOldGlobalMap.Keys) { newCmds.Add(new AssumeCmd(Token.NoToken, Expr.Binary(BinaryOperator.Opcode.Eq, new IdentifierExpr(Token.NoToken, v), Expr.Ident(ogOldGlobalMap[v])))); } newCmds.AddRange(header.Cmds); header.Cmds = newCmds; } { // Add initial block List<AssignLhs> lhss = new List<AssignLhs>(); List<Expr> rhss = new List<Expr>(); Dictionary<string, Expr> domainNameToExpr = new Dictionary<string, Expr>(); foreach (var domainName in linearTypeChecker.linearDomains.Keys) { domainNameToExpr[domainName] = new IdentifierExpr(Token.NoToken, domainNameToInputVar[domainName]); } for (int i = 0; i < impl.InParams.Count - linearTypeChecker.linearDomains.Count; i++) { Variable v = impl.InParams[i]; var domainName = linearTypeChecker.FindDomainName(v); if (domainName == null) continue; var domain = linearTypeChecker.linearDomains[domainName]; IdentifierExpr ie = new IdentifierExpr(Token.NoToken, v); domainNameToExpr[domainName] = new NAryExpr(Token.NoToken, new FunctionCall(domain.mapOrBool), new List<Expr> { v.TypedIdent.Type is MapType ? ie : linearTypeChecker.Singleton(ie, domainName), domainNameToExpr[domainName] }); } foreach (string domainName in linearTypeChecker.linearDomains.Keys) { lhss.Add(new SimpleAssignLhs(Token.NoToken, new IdentifierExpr(Token.NoToken, domainNameToLocalVar[domainName]))); rhss.Add(domainNameToExpr[domainName]); } foreach (Variable g in ogOldGlobalMap.Keys) { lhss.Add(new SimpleAssignLhs(Token.NoToken, Expr.Ident(ogOldGlobalMap[g]))); rhss.Add(Expr.Ident(g)); } if (lhss.Count > 0) { Block initBlock = new Block(Token.NoToken, "og_init", new List<Cmd> { new AssignCmd(Token.NoToken, lhss, rhss) }, new GotoCmd(Token.NoToken, new List<String> { impl.Blocks[0].Label }, new List<Block> { impl.Blocks[0] })); impl.Blocks.Insert(0, initBlock); } } CreateYieldCheckerImpl(impl, yields, map); }