diff --git a/compiler/forget/src/Optimization/DeadCodeElimination.ts b/compiler/forget/src/Optimization/DeadCodeElimination.ts index 23a6394bb0..41af43e617 100644 --- a/compiler/forget/src/Optimization/DeadCodeElimination.ts +++ b/compiler/forget/src/Optimization/DeadCodeElimination.ts @@ -5,7 +5,7 @@ * LICENSE file in the root directory of this source tree. */ -import { HIRFunction, Identifier, InstructionValue } from "../HIR"; +import { BlockId, HIRFunction, Identifier, InstructionValue } from "../HIR"; import { eachInstructionValueOperand, eachTerminalOperand, @@ -20,11 +20,13 @@ import { assertExhaustive, retainWhere } from "../Utils/utils"; export function deadCodeElimination(fn: HIRFunction): void { const used = new Set(); - // TODO: ensure a single iteration of the CFG if there are no back-edges, - // see EliminateRedundantPhi.ts for an example - let lastSize = -1; - while (used.size > lastSize) { - lastSize = used.size; + // If there are no back-edges the algorithm can terminate after a single iteration + // of the blocks + const hasLoop = hasBackEdge(fn); + + let size = used.size; + do { + size = used.size; // Iterate blocks in postorder (successors before predecessors, excepting loops) // to find usages before declarations @@ -57,7 +59,7 @@ export function deadCodeElimination(fn: HIRFunction): void { } } } - } + } while (used.size > size && hasLoop); for (const [, block] of fn.body.blocks) { for (const phi of block.phis) { if (!used.has(phi.id)) { @@ -115,3 +117,16 @@ function pruneableValue(value: InstructionValue): boolean { } } } + +function hasBackEdge(fn: HIRFunction): boolean { + const visited = new Set(); + for (const [blockId, block] of fn.body.blocks) { + for (const predId of block.preds) { + if (!visited.has(predId)) { + return true; + } + } + visited.add(blockId); + } + return false; +}