def main(**kwargs): the_program = programs.IO.read(kwargs['program']) the_program.call_graph.dotify() if kwargs['manual']: programs.IO.read_properties(the_program, kwargs['manual']) else: instrumentation_id = 0 for subprogram in the_program: ppg = graphs.ProgramPointGraph.create_from_control_flow_graph( subprogram.cfg) ppg.dotify() ppg.choose_instrumentation() old_to_new = {v: v for v in subprogram.cfg} for v in ppg: if isinstance(v.program_point, vertices.Vertex): instrumentation_id += 1 instrumentation = vertices.InstrumentationVertex( vertices.Vertex.get_vertex_id(), ppg.name, instrumentation_id) subprogram.cfg.add_vertex(instrumentation) old_to_new[v.program_point] = instrumentation if subprogram.cfg.entry == v.program_point: subprogram.cfg.entry = instrumentation if subprogram.cfg.exit == v.program_point: subprogram.cfg.exit = instrumentation for edge in subprogram.cfg.successors(v.program_point): subprogram.cfg.add_edge( edges.ControlFlowEdge(instrumentation, edge.successor())) for edge in subprogram.cfg.predecessors(v.program_point): subprogram.cfg.add_edge( edges.ControlFlowEdge(edge.predecessor(), instrumentation)) subprogram.cfg.remove_vertex(v.program_point) for v in ppg: if isinstance(v.program_point, edges.Edge): instrumentation_id += 1 predecessor = old_to_new[v.program_point.predecessor()] successor = old_to_new[v.program_point.successor()] subprogram.cfg.remove_edge( edges.ControlFlowEdge(predecessor, successor)) subprogram.cfg.add_edge( edges.InstrumentationEdge(predecessor, successor, instrumentation_id)) programs.IO.write(the_program, kwargs['output'])
def connect_nested_loops(self, cfg, nested_loops): highest_level = max(self.level_to_vertices.keys()) candidate_entry_sources = [ v for v in self._vertices if 0 < self._vertex_to_level[v] < highest_level ] for loop in nested_loops: (p, ) = sample(candidate_entry_sources, 1) cfg.add_edge(edges.ControlFlowEdge(p, loop.header)) for exit_source in loop.exits: higher_level = randint(self._vertex_to_level[p] + 1, highest_level) candidate_exit_destinations = self.level_to_vertices[ higher_level] (s, ) = sample(candidate_exit_destinations, 1) cfg.add_edge(edges.ControlFlowEdge(exit_source, s))
def parse(cls, line): lexemes = line.split() if lexemes: time = int(lexemes[-1]) if len(lexemes) == 2: v = vertices.Vertex.id_pool[int(lexemes[0])] return v, time else: p = vertices.Vertex.id_pool[int(lexemes[0])] s = vertices.Vertex.id_pool[int(lexemes[1])] edge = edges.ControlFlowEdge(p, s) return edge, time
def add_edges(self, cfg, fan_out): for level in sorted(self.level_to_vertices.keys(), reverse=True): if level > 0: for s in self.level_to_vertices[level]: candidates = [ v for v in self.level_to_vertices[level - 1] if len(cfg.successors(v)) < fan_out ] (p, ) = sample(candidates, 1) cfg.add_edge(edges.ControlFlowEdge(p, s)) if len(cfg.successors(p)) == fan_out: candidates.remove(p)
def connect_terminal_vertices(self, cfg): highest_level = max(self.level_to_vertices.keys()) for level in sorted(self.level_to_vertices.keys(), reverse=True): if 0 < level < highest_level: candidate_predecessors = [ v for v in self.level_to_vertices[level] if len(cfg.successors(v)) == 0 ] higher_level = randint(level + 1, highest_level) candidate_successors = self.level_to_vertices[higher_level] for p in candidate_predecessors: (s, ) = sample(candidate_successors, 1) cfg.add_edge(edges.ControlFlowEdge(p, s))
def read(cls, filename: str) -> Program: messages.debug_message("Reading program from '{}'".format(filename)) program = Program(filename) cfgs = [] calls = [] with open(filename) as json_file: program_json = json.load(json_file) magic_info = program_json[0] program.magic = magic_info[1] subprograms_json = program_json[1] for subprogram_name, (vertices_json, edges_json) in subprograms_json.items(): cfg = graphs.ControlFlowGraph(program, subprogram_name) cfgs.append(cfg) for vertex_json in vertices_json: vertex_id = int(vertex_json[0]) vertex = vertices.BasicBlock(int(vertex_id)) cfg.add_vertex(vertex) instruction_json = vertex_json[1] for instruction_text in instruction_json: if instruction_text[ 0] == instructions.CallInstruction.OPCODE: callee = instruction_text[1] calls.append([cfg.name, callee, vertex]) vertex.instructions.append( instructions.CallInstruction(callee)) elif instruction_text[ 0] == instructions.BranchInstruction.OPCODE: vertex.instructions.append( instructions.BranchInstruction()) elif instruction_text[ 0] == instructions.StoreInstruction.OPCODE: vertex.instructions.append( instructions.StoreInstruction()) elif instruction_text[ 0] == instructions.LoadInstruction.OPCODE: vertex.instructions.append( instructions.LoadInstruction()) elif instruction_text[ 0] == instructions.AddInstruction.OPCODE: vertex.instructions.append( instructions.AddInstruction()) elif instruction_text[ 0] == instructions.SubtractInstruction.OPCODE: vertex.instructions.append( instructions.SubtractInstruction()) elif instruction_text[ 0] == instructions.MultiplyInstruction.OPCODE: vertex.instructions.append( instructions.MultiplyInstruction()) elif instruction_text[ 0] == instructions.DivideInstruction.OPCODE: vertex.instructions.append( instructions.DivideInstruction()) for edge_json in edges_json: predecessor_id, successor_id = edge_json predecessor = vertices.Vertex.id_pool[int(predecessor_id)] successor = vertices.Vertex.id_pool[int(successor_id)] cfg.add_edge(edges.ControlFlowEdge(predecessor, successor)) for cfg in cfgs: call = vertices.SubprogramVertex(vertices.Vertex.get_vertex_id(), cfg.name) subprogram = Subprogram(cfg, call) program.add_subprogram(subprogram) for vertex in cfg: if len(cfg.predecessors(vertex)) == 0: assert cfg.entry is None cfg.entry = vertex if len(cfg.successors(vertex)) == 0: assert cfg.exit is None cfg.exit = vertex cfg.add_edge(edges.ControlFlowEdge(cfg.exit, cfg.entry)) for caller, callee, site in calls: caller = program[caller].call_vertex callee = program[callee].call_vertex program.call_graph.add_edge( edges.CallGraphEdge(caller, callee, site)) return program
def create_control_flow_graph(program, loops, nesting_depth, dense, irreducible, number_of_vertices, fan_out, subprg_name): def create_artificial_loop_hierarchy(): # Add abstract vertices to the tree, including an extra one # for the dummy outer loop lnt = graphs.DirectedGraph() for _ in range(1, loops + 2): lnt.add_vertex(vertices.Vertex(vertices.Vertex.get_vertex_id())) # Add edges to the tree vertex_to_level = {vertex: 0 for vertex in lnt} (root_vertex, ) = sample(vertex_to_level.keys(), 1) parent_vertex = root_vertex for vertex in lnt: if vertex != root_vertex: new_level = vertex_to_level[parent_vertex] + 1 if new_level <= nesting_depth: lnt.add_edge(edges.Edge(parent_vertex, vertex)) vertex_to_level[vertex] = new_level else: # The height of the tree now exceeds the maximum depth, so # backtrack to an arbitrary proper ancestor ancestor_vertex = parent_vertex while True: (edge, ) = lnt.predecessors(ancestor_vertex) ancestor_vertex = edge.predecessor() if go_ahead() or ancestor_vertex == root_vertex: break parent_vertex = ancestor_vertex lnt.add_edge(edges.Edge(parent_vertex, vertex)) vertex_to_level[ vertex] = vertex_to_level[parent_vertex] + 1 parent_vertex = vertex # Compute number of vertices in each loop number_of_vertices_remaining = number_of_vertices for vertex in lnt: # Guarantee each loop has at least 2 vertices plus vertices needed # to connect inner nested loops vertex.size = 2 + len(lnt.successors(vertex)) number_of_vertices_remaining -= vertex.size # Arbitrarily distribute any remaining vertices to the loop bodies while number_of_vertices_remaining > 0: for vertex in lnt: additional_vertices = randint(0, number_of_vertices_remaining) vertex.size += additional_vertices number_of_vertices_remaining -= additional_vertices return lnt, root_vertex def create_loop_body(vertex): for edge in lnt.successors(vertex): create_loop_body(edge.successor()) # Post-order actions nested_loops = [ loops[edge.successor()] for edge in lnt.successors(vertex) ] loops[vertex] = ArtificialLoopBody(fan_out, cfg, vertex.size, nested_loops, len(lnt.predecessors(vertex)) == 0) if len(lnt.predecessors(vertex)) == 0: (edge, ) = cfg.predecessors(loops[vertex].header) cfg.entry = edge.successor() cfg.exit = edge.predecessor() cfg = graphs.ControlFlowGraph(program, subprg_name) if not irreducible: lnt, root_vertex = create_artificial_loop_hierarchy() loops = {} create_loop_body(root_vertex) else: loop = ArtificialLoopBody(fan_out, cfg, number_of_vertices, [], True) (edge, ) = cfg.predecessors(loop.header) cfg.entry = edge.successor() cfg.exit = edge.predecessor() candidates = [ vertex for vertex in cfg if vertex != cfg.entry and vertex != cfg.exit ] min_level = min(loop.level_to_vertices.keys()) max_level = max(loop.level_to_vertices.keys()) candidate_levels = [level for level in range(min_level + 1, max_level)] if dense: max_edges = len(candidates) * len(candidates) * len(candidates) else: max_edges = len(candidates) + int(len(candidates) / 2) level_edges = randint(1, max_edges) anywhere_edges = max_edges - level_edges start = time() if len(candidate_levels) > 2: for _ in range(level_edges): p_level = choice(candidate_levels[2:]) s_level = choice(candidate_levels[:p_level - 1]) p = choice(loop.level_to_vertices[p_level]) s = choice(loop.level_to_vertices[s_level]) if not cfg.has_edge(p, s): cfg.add_edge(edges.ControlFlowEdge(p, s)) if time() - start > 5: break start = time() for _ in range(anywhere_edges): p = choice(candidates) s = choice(candidates) if not cfg.has_edge(p, s): cfg.add_edge(edges.ControlFlowEdge(p, s)) if time() - start > 5: break return cfg
def add_backedges(self, cfg): highest_level = max(self.level_to_vertices.keys()) for v in self.level_to_vertices[highest_level]: cfg.add_edge(edges.ControlFlowEdge(v, self._header))