[NotNull] private static IReadOnlyDictionary <IBasicBlock, IMutableBasicBlock> CloneVertices( [NotNull] this IControlFlowGraph input, IMutableControlFlowGraph output, [NotNull] Func <IBasicBlock, bool> keep, [CanBeNull] Action <IBasicBlock, IMutableBasicBlock> copy = null ) { // Clone vertices (without edges) var replacements = new Dictionary <IBasicBlock, IMutableBasicBlock>(); foreach (var vertex in input.Vertices.Where(keep)) { var r = output.CreateNewBlock(vertex.Type, vertex.LineNumber, vertex.ID); replacements.Add(vertex, r); if (copy != null) { copy(vertex, r); } else { foreach (var stmt in vertex.Statements) { r.Add(stmt); } } } return(replacements); }
private IMutableBasicBlock GetLineEntryBlock(IMutableControlFlowGraph cfg, int lineNumber) { if (!_lineStartBlocks.TryGetValue(lineNumber, out var block)) { block = cfg.CreateNewBlock(BasicBlockType.LineStart, lineNumber); _lineStartBlocks.Add(lineNumber, block); } return(block); }
/// <summary> /// Convert a statement list into basic blocks. Return the final block that was created if it needs to be connected to the next block /// </summary> /// <param name="cfg"></param> /// <param name="statements"></param> /// <param name="lineNumber"></param> /// <param name="entry"></param> /// <returns>(entry_block!, exit_block?)</returns> private (IMutableBasicBlock, IMutableBasicBlock) HandleStatementList(IMutableControlFlowGraph cfg, StatementList statements, int lineNumber, IMutableBasicBlock entry) { var block = cfg.CreateNewBlock(BasicBlockType.Basic, lineNumber); cfg.CreateEdge(entry, block, EdgeType.Continue); foreach (var stmt in statements.Statements) { if (stmt is Goto @goto) { HandleGoto(cfg, @goto, block, lineNumber); // Create a new block which is _not_ linked to the previous (because we just unconditionally jumped away) block = cfg.CreateNewBlock(BasicBlockType.Basic, lineNumber); } else if (stmt is If @if) { block.Add(new Conditional(@if.Condition)); // Convert true and false branches into blocks var(enTrue, exTrue) = HandleStatementList(cfg, @if.TrueBranch, lineNumber, cfg.CreateNewBlock(BasicBlockType.Basic, lineNumber)); var(enFals, exFals) = HandleStatementList(cfg, @if.FalseBranch, lineNumber, cfg.CreateNewBlock(BasicBlockType.Basic, lineNumber)); // Create edges from conditional to two branches cfg.CreateEdge(block, enTrue, EdgeType.ConditionalTrue); cfg.CreateEdge(block, enFals, EdgeType.ConditionalFalse); // Link the exit blocks (if they're not null) to the next block block = cfg.CreateNewBlock(BasicBlockType.Basic, lineNumber); if (exTrue != null) { cfg.CreateEdge(exTrue, block, EdgeType.Continue); } if (exFals != null) { cfg.CreateEdge(exFals, block, EdgeType.Continue); } } else if (stmt is EmptyStatement) { // ignore empty statements, they (obviously) don't do anything // ReSharper disable once RedundantJumpStatement continue; } else { // Add to block with fallthrough to next line if it can error block.Add(stmt); if (stmt.CanRuntimeError) { AddFallthrough(cfg, block, lineNumber, EdgeType.RuntimeError); var b2 = cfg.CreateNewBlock(BasicBlockType.Basic, block.LineNumber); cfg.CreateEdge(block, b2, EdgeType.Continue); block = b2; } } } return(entry, block); }