private static LiveVariables ComputeLiveness(ControlFlowGraph function, Edges edges) { var blocks = new Queue <BasicBlock>(); blocks.EnqueueRange(function.ExitBlocks); var liveVariables = new LiveVariables(function); var numberOfVariables = function.VariableDeclarations.Count; while (blocks.TryDequeue(out var block)) { var liveBeforeBlock = new BitArray(liveVariables.Before(block.Statements.First())); var liveAfterBlock = new BitArray(numberOfVariables); foreach (var successor in edges.From(block)) { liveAfterBlock.Or(liveVariables.Before(successor.Statements.Last())); } var liveAfterStatement = liveAfterBlock; foreach (var statement in block.Statements.Reverse()) { var liveSet = liveVariables.Before(statement); liveSet.Or(liveAfterStatement); switch (statement) { case AssignmentStatement assignment: KillVariables(liveSet, assignment.Place); EnlivenVariables(liveSet, assignment.Value); break; case ActionStatement action: EnlivenVariables(liveSet, action.Value); break; case DeleteStatement _: throw new InvalidOperationException("Delete statements are supposed to be added after liveness analysis"); //liveSet[deleteStatement.Place.CoreVariable()] = true; //break; case IfStatement _: case GotoStatement _: // We already or'ed together the live variables from successor blocks break; case ReturnStatement _: // No effect on variables? // TODO should we check the liveSet is empty? break; default: throw NonExhaustiveMatchException.For(statement); } // For the next statement liveAfterStatement = liveSet; } if (!liveBeforeBlock.ValuesEqual(liveVariables.Before(block.Statements.First()))) { foreach (var basicBlock in edges.To(block) .Where(fromBlock => !blocks.Contains(fromBlock)).ToList()) { blocks.Enqueue(basicBlock); } } } return(liveVariables); }