1/* 2 * Copyright (c) 2025 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16/** 17 * Reaching Definitions Data Flow Analysis 18 * 19 * This module implements the Reaching Definitions data flow analysis algorithm. 20 * Reaching Definitions is a forward data flow analysis that determines, for each 21 * program point, the set of variable definitions (assignments) that may reach 22 * that point without being overwritten. 23 * 24 * Key Components: 25 * 1. **Transfer Function**: 26 * - Computes the out set for each node based on its in set. 27 * - Uses gen and kill sets to model the effects of assignments: 28 * - **gen**: The set of definitions generated by the current node. 29 * - **kill**: The set of definitions killed (overwritten) by the current node. 30 * 31 * 2. **Meet Operation**: 32 * - Combines data flow values from multiple paths (e.g., union for reaching definitions). 33 * - Ensures that the analysis is conservative (safe) by over-approximating the result. 34 * 35 * The analysis is forward, meaning it propagates information from predecessors to successors. 36 * 37 */ 38 39import { ArkAssignStmt, Stmt } from '../base/Stmt'; 40import { Value } from '../base/Value'; 41import { BaseImplicitGraph, NodeID } from '../graph/BaseImplicitGraph'; 42import { ArkMethod } from '../model/ArkMethod'; 43import { DataFlowProblem, TransferFunction, FlowGraph } from './GenericDataFlow'; 44import { SparseBitVector } from '../../utils/SparseBitVector'; 45import { Cfg } from '../graph/Cfg'; 46 47type RDNode = Stmt; 48type DFNodeCollection = SparseBitVector; 49let coCtor: new (s: number) => SparseBitVector = SparseBitVector; 50const BV_SIZE = 32; 51 52export class ReachingDefProblem implements DataFlowProblem<NodeID, DFNodeCollection> { 53 flowGraph: ReachingDefFlowGraph; 54 transferFunction: ReachingDefTransferFunction; 55 meet: (a: DFNodeCollection, b: DFNodeCollection) => DFNodeCollection; 56 initIn: Map<NodeID, DFNodeCollection>; 57 initOut: Map<NodeID, DFNodeCollection>; 58 forward: boolean; 59 empty: DFNodeCollection = new coCtor(BV_SIZE); 60 61 constructor(method: ArkMethod, forward: boolean = true) { 62 this.flowGraph = new ReachingDefFlowGraph(method); 63 this.transferFunction = new ReachingDefTransferFunction(this.flowGraph); 64 this.meet = (x: DFNodeCollection, y: DFNodeCollection): DFNodeCollection => { 65 let r = x.clone(); 66 r.unionWith(y); 67 return r; 68 }; 69 this.initIn = new Map(this.flowGraph.nodesInPostOrder.map(i => [i, new coCtor(BV_SIZE)])); 70 this.initOut = new Map(this.flowGraph.nodesInPostOrder.map(i => [i, new coCtor(BV_SIZE)])); 71 this.forward = forward; 72 } 73} 74 75/** 76 * Represents the control flow graph (CFG) for reaching definitions analysis. 77 * This class implements the FlowGraph interface and provides methods to retrieve 78 * successors and predecessors of nodes, as well as topological orderings of nodes. 79 */ 80class ReachingDefFlowGraph extends BaseImplicitGraph<RDNode> implements FlowGraph<NodeID> { 81 nodesInPostOrder: NodeID[]; 82 83 constructor(method: ArkMethod) { 84 super(); 85 const cfg = method.getCfg(); 86 if (!cfg) { 87 throw new Error('CFG not found'); 88 } 89 90 const nodes = cfg.getStmts(); 91 this.nodeToIdMap = new Map(nodes.map((x, i) => [x, i])); 92 this.idToNodeMap = new Map(nodes.map((x, i) => [i, x])); 93 this.nodesInPostOrder = nodes.map((_, i) => i); 94 95 this.initSuccPred(nodes, cfg); 96 } 97 98 getGraphName(): string { 99 return 'Reaching Definition Flow Graph'; 100 } 101 102 dumpNodes(): void { 103 this.nodeToIdMap?.forEach((id, node) => console.log(id + ': ' + node.toString())); 104 } 105 106 private initSuccPred(nodes: RDNode[], cfg: Cfg): void { 107 this.succMap = new Map(); 108 this.predMap = new Map(); 109 110 cfg.getBlocks().forEach(bb => { 111 let stmts = bb.getStmts(); 112 if (stmts.length === 0) { 113 return; 114 } 115 116 for (let i = 0; i < stmts.length - 1; i++) { 117 let c = this.nodeToIdMap!.get(stmts[i])!; 118 let n = this.nodeToIdMap!.get(stmts[i + 1])!; 119 if (c === undefined || n === undefined) { 120 continue; 121 } 122 this.succMap.set(c, [n]); 123 this.predMap.set(n, [c]); 124 } 125 126 let terminate = bb.getTail(); 127 if (!terminate) { 128 throw new Error('cfg has no terminal'); 129 } 130 131 let successors = bb.getSuccessors(); 132 // try...catch语句,catch所在的block在CFG表示里是没有前驱block的,需要在这里额外查找并将exceptionalSuccessorBlocks作为try块的后继块之一 133 const exceptionalSuccessorBlocks = bb.getExceptionalSuccessorBlocks(); 134 if (exceptionalSuccessorBlocks !== undefined) { 135 successors.push(...exceptionalSuccessorBlocks); 136 } 137 successors.forEach(succBB => { 138 let head = succBB.getHead(); 139 if (!head) { 140 return; 141 } 142 let t = this.nodeToIdMap?.get(terminate!)!; 143 let h = this.nodeToIdMap?.get(head)!; 144 if (t === undefined || h === undefined) { 145 return; 146 } 147 // Terminate's succ 148 let succ = this.succMap.get(t) ?? []; 149 succ.push(h); 150 this.succMap.set(t, succ); 151 152 // Head's pred 153 let pred = this.predMap.get(h) ?? []; 154 pred.push(t); 155 this.predMap.set(h, pred); 156 }); 157 }); 158 } 159} 160 161/** 162 * Represents the transfer function for reaching definitions analysis. 163 */ 164export class ReachingDefTransferFunction implements TransferFunction<NodeID, DFNodeCollection> { 165 gen: DFNodeCollection; 166 kill: Map<NodeID, DFNodeCollection>; 167 168 constructor(flowGraph: ReachingDefFlowGraph) { 169 this.gen = new coCtor(BV_SIZE); 170 this.kill = new Map(); 171 this.initGenKill(flowGraph); 172 } 173 174 apply(n: NodeID, x: DFNodeCollection): DFNodeCollection { 175 const result = x.clone(); 176 if (this.gen.test(n)) { 177 result.set(n); 178 } 179 180 const killSet = this.kill.get(n); 181 if (killSet) { 182 for (const item of killSet) { 183 result.reset(item); 184 } 185 } 186 return result; 187 } 188 189 private initGenKill(g: ReachingDefFlowGraph): void { 190 let genValue2Nodes: Map<Value, DFNodeCollection> = new Map(); 191 // Init Gen 192 g.getNodeToIdMap().forEach((id, node) => { 193 if (node instanceof ArkAssignStmt) { 194 let lop = node.getLeftOp(); 195 let genNodes = genValue2Nodes.get(lop) ?? new coCtor(BV_SIZE); 196 genNodes.set(id); 197 genValue2Nodes.set(lop, genNodes); 198 this.gen.set(id); 199 } 200 }); 201 202 // Init Kill 203 genValue2Nodes.forEach((defNodes, v) => { 204 for (const i of defNodes) { 205 const killSet = defNodes.clone(); 206 killSet.reset(i); 207 this.kill.set(i, killSet); 208 } 209 }); 210 } 211} 212