From 5e2130c1d30af30b212b4353b15cf3e557171d4a Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 16 Mar 2026 10:31:43 +0000 Subject: [PATCH] Extract FunctionControlFlowInfo from SSA and decouple CFG building Extracts the basic-block linearisation and CFG construction into a new, standalone opt.FunctionControlFlowInfo struct so that any opt pass (e.g. constant propagation, liveness analysis) can obtain the CFG without constructing a full SSA info object. FunctionSsaInfo is updated to embed opt.FunctionControlFlowInfo instead of duplicating the same fields; no behaviour changes. https://claude.ai/code/session_0165cPFCURfazKMvWB6yPZBa --- opt/function_control_flow_info.go | 49 +++++++++++++++++++++++++++++++ opt/ssa/function_ssa_info.go | 48 ++++++------------------------ 2 files changed, 58 insertions(+), 39 deletions(-) create mode 100644 opt/function_control_flow_info.go diff --git a/opt/function_control_flow_info.go b/opt/function_control_flow_info.go new file mode 100644 index 0000000..981dbda --- /dev/null +++ b/opt/function_control_flow_info.go @@ -0,0 +1,49 @@ +package opt + +import ( + "alon.kr/x/graph" + "alon.kr/x/usm/gen" +) + +// FunctionControlFlowInfo holds the flattened basic-block list, the +// block-to-index mapping, and the control-flow graph for a function. It is +// derived purely from gen.FunctionInfo and can be used by any pass that needs +// CFG traversal (e.g. constant propagation, liveness analysis) or block-index +// lookups (e.g. SSA construction). +type FunctionControlFlowInfo struct { + // A linear representation of all basic blocks in the function. + BasicBlocks []*gen.BasicBlockInfo + + // Maps each basic block to its index in BasicBlocks. + BasicBlocksToIndex map[*gen.BasicBlockInfo]uint + + ControlFlowGraph *graph.Graph +} + +// NewFunctionControlFlowInfo builds a FunctionControlFlowInfo from the given +// function by linearising its basic blocks and constructing the CFG from their +// forward edges. +func NewFunctionControlFlowInfo(function *gen.FunctionInfo) FunctionControlFlowInfo { + basicBlocks := function.CollectBasicBlocks() + + blockToIndex := make(map[*gen.BasicBlockInfo]uint, len(basicBlocks)) + for i, b := range basicBlocks { + blockToIndex[b] = uint(i) + } + + forwardEdges := make([][]uint, len(basicBlocks)) + for i, b := range basicBlocks { + edges := make([]uint, 0, len(b.ForwardEdges)) + for _, target := range b.ForwardEdges { + edges = append(edges, blockToIndex[target]) + } + forwardEdges[i] = edges + } + + cfg := graph.NewGraph(forwardEdges) + return FunctionControlFlowInfo{ + BasicBlocks: basicBlocks, + BasicBlocksToIndex: blockToIndex, + ControlFlowGraph: &cfg, + } +} diff --git a/opt/ssa/function_ssa_info.go b/opt/ssa/function_ssa_info.go index 390d092..18d6fd5 100644 --- a/opt/ssa/function_ssa_info.go +++ b/opt/ssa/function_ssa_info.go @@ -8,6 +8,7 @@ import ( "alon.kr/x/set" "alon.kr/x/usm/core" "alon.kr/x/usm/gen" + "alon.kr/x/usm/opt" ) type forwardingRegisterDescriptor struct { @@ -75,14 +76,11 @@ func (p *phiInstructionDescriptor) CommitForwardingRegisters() core.ResultList { type FunctionSsaInfo struct { *gen.FunctionInfo - SsaConstructionScheme SsaConstructionScheme - - // A linear representation of all basic blocks in the function. - BasicBlocks []*gen.BasicBlockInfo + // Embeds the basic-block list, block-to-index mapping, and CFG that are + // shared with other passes (e.g. constant propagation). + opt.FunctionControlFlowInfo - // A mapping between all basic blocks in the function and their index in the - // Blocks slice. - BasicBlocksToIndex map[*gen.BasicBlockInfo]uint + SsaConstructionScheme SsaConstructionScheme // A mapping between all basic blocks and the phi instructions that they // define in their entry. @@ -96,7 +94,6 @@ type FunctionSsaInfo struct { // A mapping from (base) registers to their index in the registers slice. RegistersToIndex map[*gen.RegisterInfo]uint - ControlFlowGraph *graph.Graph DominatorJoinGraph *graph.DominatorJoinGraph } @@ -104,24 +101,19 @@ func NewFunctionSsaInfo( function *gen.FunctionInfo, ssaConstructionScheme SsaConstructionScheme, ) FunctionSsaInfo { - basicBlocks := function.CollectBasicBlocks() - basicBlockToIndex := createMappingToIndex(basicBlocks) - forwardEdges := getBasicBlocksForwardEdges(basicBlocks, basicBlockToIndex) - graph := graph.NewGraph(forwardEdges) - dominatorJoinGraph := graph.DominatorJoinGraph(0) + cfInfo := opt.NewFunctionControlFlowInfo(function) + dominatorJoinGraph := cfInfo.ControlFlowGraph.DominatorJoinGraph(0) baseRegisters := function.Registers.GetAllRegisters() registersToIndex := createMappingToIndex(baseRegisters) return FunctionSsaInfo{ FunctionInfo: function, + FunctionControlFlowInfo: cfInfo, SsaConstructionScheme: ssaConstructionScheme, - BasicBlocks: basicBlocks, - BasicBlocksToIndex: basicBlockToIndex, - PhiInstructionsPerBlock: make([][]phiInstructionDescriptor, len(basicBlocks)), + PhiInstructionsPerBlock: make([][]phiInstructionDescriptor, len(cfInfo.BasicBlocks)), BaseRegisters: baseRegisters, RegistersToIndex: registersToIndex, - ControlFlowGraph: &graph, DominatorJoinGraph: &dominatorJoinGraph, } } @@ -136,28 +128,6 @@ func createMappingToIndex[T comparable]( return mapping } -func getSingleBasicBlockForwardEdges( - block *gen.BasicBlockInfo, - basicBlockToIndex map[*gen.BasicBlockInfo]uint, -) []uint { - indices := make([]uint, 0, len(block.ForwardEdges)) - for _, targetBlock := range block.ForwardEdges { - indices = append(indices, basicBlockToIndex[targetBlock]) - } - return indices -} - -func getBasicBlocksForwardEdges( - blocks []*gen.BasicBlockInfo, - basicBlockToIndex map[*gen.BasicBlockInfo]uint, -) [][]uint { - edges := make([][]uint, len(blocks)) - for i, block := range blocks { - edges[i] = getSingleBasicBlockForwardEdges(block, basicBlockToIndex) - } - return edges -} - // Returns all the basic blocks in which the provided register is defined. func (i *FunctionSsaInfo) getDefinitions( register *gen.RegisterInfo,