from__future__importannotationsimportnetworkxfromailment.expressionimportVirtualVariablefromailment.statementimportAssignment,Callfromangr.analysesimportAnalysis,register_analysisfromangr.utils.ssaimportVVarUsesCollector,phi_assignment_get_srcclassSLivenessModel:""" The SLiveness model that stores LiveIn and LiveOut sets for each block in a partial-SSA function. """def__init__(self):self.live_ins={}self.live_outs={}
[文档]classSLivenessAnalysis(Analysis):""" Calculates LiveIn and LiveOut sets for each block in a partial-SSA function. """
def_analyze(self):graph=self.func_graphentry=self.entry# initialize the live_in and live_out setslive_ins={}live_outs={}forblockingraph.nodes():block_key=block.addr,block.idxlive_ins[block_key]=set()live_outs[block_key]=set()live_on_edges:dict[tuple[tuple[int,int|None],tuple[int,int|None]],set[int]]={}worklist=list(networkx.dfs_postorder_nodes(graph,source=entry))worklist_set=set(worklist)whileworklist:block=worklist.pop(0)worklist_set.remove(block)block_key=block.addr,block.idxchanged=Falselive=set()forsuccingraph.successors(block):edge=(block.addr,block.idx),(succ.addr,succ.idx)ifedgeinlive_on_edges:live|=live_on_edges[edge]else:live|=live_ins[(succ.addr,succ.idx)]iflive!=live_outs[block_key]:changed=Truelive_outs[block_key]=live.copy()live_in_by_pred={}forstmtinreversed(block.statements):# handle assignments: a defined vvar is not live before the assignmentifisinstance(stmt,Assignment)andisinstance(stmt.dst,VirtualVariable):live.discard(stmt.dst.varid)elifisinstance(stmt,Call)andisinstance(stmt.ret_expr,VirtualVariable):live.discard(stmt.ret_expr.varid)phi_expr=phi_assignment_get_src(stmt)ifphi_exprisnotNone:forsrc,vvarinphi_expr.src_and_vvars:ifsrcnotinlive_in_by_pred:live_in_by_pred[src]=live.copy()ifvvarisnotNone:live_in_by_pred[src].add(vvar.varid)live_in_by_pred[src].discard(stmt.dst.varid)# handle the statement: add used vvars to the live setvvar_use_collector=VVarUsesCollector()vvar_use_collector.walk_statement(stmt)live|=vvar_use_collector.vvarsiflive_ins[block_key]!=live:live_ins[block_key]=livechanged=Trueforpred_addr,liveinlive_in_by_pred.items():key=pred_addr,block_keyifkeynotinlive_on_edgesorlive_on_edges[key]!=live:live_on_edges[key]=livechanged=Trueifchanged:new_nodes=[nodefornodeinnetworkx.dfs_postorder_nodes(graph,source=block)ifnodenotinworklist_set]worklist.extend(new_nodes)worklist_set|=set(new_nodes)# set the model accordinglyself.model.live_ins=live_insself.model.live_outs=live_outs
[文档]definterference_graph(self)->networkx.Graph:""" Generate an interference graph based on the liveness analysis result. :return: A networkx.Graph instance. """graph=networkx.Graph()forblockinself.func_graph.nodes():live=self.model.live_outs[(block.addr,block.idx)].copy()forstmtinreversed(block.statements):ifisinstance(stmt,Assignment)andisinstance(stmt.dst,VirtualVariable):def_vvar=stmt.dst.varidelifisinstance(stmt,Call)andisinstance(stmt.ret_expr,VirtualVariable):def_vvar=stmt.ret_expr.varidelse:def_vvar=None# handle the statement: add used vvars to the live setvvar_use_collector=VVarUsesCollector()vvar_use_collector.walk_statement(stmt)ifdef_vvarisnotNone:forlive_vvarinlive:graph.add_edge(def_vvar,live_vvar)live.discard(def_vvar)live|=vvar_use_collector.vvarsifblock.addr==self.func_addr:# deal with function argumentsforarg_vvarinself.arg_vvars:forlive_vvarinlive:graph.add_edge(arg_vvar.varid,live_vvar)returngraph