From 225fe0835cc34139ee8644dd4fd01e48f3d952d4 Mon Sep 17 00:00:00 2001 From: Joe Savona Date: Mon, 13 Feb 2023 13:59:44 -0800 Subject: [PATCH] Optimize DCE to visit CFG only once when there are no loops Optimizes dead code elimination. Currently it keeps iterating the control flow graph until no new usages have been discovered, which accounts for usages across loops. However, when there are no loops it's sufficient to iterate the CFG exactly once. --- .../src/Optimization/DeadCodeElimination.ts | 29 ++++++++++++++----- 1 file changed, 22 insertions(+), 7 deletions(-) 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; +}