def check_assembler(self, graph, expected, transform=False, callcontrol=None): # 'transform' can be False only for simple graphs. More complex # graphs must first be transformed by jtransform.py before they can be # subjected to register allocation and flattening. if transform: from rpython.jit.codewriter.jtransform import transform_graph transform_graph(graph, callcontrol=callcontrol) regalloc = perform_register_allocation(graph, 'int') regalloc2 = perform_register_allocation(graph, 'ref') ssarepr = flatten_graph(graph, {'int': regalloc, 'ref': regalloc2}) assert_format(ssarepr, expected)
def transform_graph_to_jitcode(self, graph, jitcode, verbose): """Transform a graph into a JitCode containing the same bytecode in a different format. """ portal_jd = self.callcontrol.jitdriver_sd_from_portal_graph(graph) graph = copygraph(graph, shallowvars=True) # # step 1: mangle the graph so that it contains the final instructions # that we want in the JitCode, but still as a control flow graph transform_graph(graph, self.cpu, self.callcontrol, portal_jd) # # step 2: perform register allocation on it regallocs = {} for kind in KINDS: regallocs[kind] = perform_register_allocation(graph, kind) # # step 3: flatten the graph to produce human-readable "assembler", # which means mostly producing a linear list of operations and # inserting jumps or conditional jumps. This is a list of tuples # of the shape ("opname", arg1, ..., argN) or (Label(...),). ssarepr = flatten_graph(graph, regallocs) # # step 3b: compute the liveness around certain operations compute_liveness(ssarepr) # # step 4: "assemble" it into a JitCode, which contains a sequence # of bytes and lists of constants. It's during this step that # constants are cast to their normalized type (Signed, GCREF or # Float). self.assembler.assemble(ssarepr, jitcode) # # print the resulting assembler if self.debug: self.print_ssa_repr(ssarepr, portal_jd, verbose)
def transform_graph_to_jitcode(self, graph, jitcode, verbose, index): """Transform a graph into a JitCode containing the same bytecode in a different format. """ portal_jd = self.callcontrol.jitdriver_sd_from_portal_graph(graph) graph = copygraph(graph, shallowvars=True) # # step 1: mangle the graph so that it contains the final instructions # that we want in the JitCode, but still as a control flow graph transform_graph(graph, self.cpu, self.callcontrol, portal_jd) # # step 2: perform register allocation on it regallocs = {} for kind in KINDS: regallocs[kind] = perform_register_allocation(graph, kind) # # step 3: flatten the graph to produce human-readable "assembler", # which means mostly producing a linear list of operations and # inserting jumps or conditional jumps. This is a list of tuples # of the shape ("opname", arg1, ..., argN) or (Label(...),). ssarepr = flatten_graph(graph, regallocs, cpu=self.callcontrol.cpu) # # step 3b: compute the liveness around certain operations compute_liveness(ssarepr) # # step 4: "assemble" it into a JitCode, which contains a sequence # of bytes and lists of constants. It's during this step that # constants are cast to their normalized type (Signed, GCREF or # Float). self.assembler.assemble(ssarepr, jitcode) jitcode.index = index # # print the resulting assembler if self.debug: self.print_ssa_repr(ssarepr, portal_jd, verbose)
def test_regalloc_void(self): def f(a, b): while a > 0: b += a a -= 1 return b graph = self.make_graphs(f, [5, 6])[0] regalloc = perform_register_allocation(graph, 'float')
def test_regalloc_simple(self): def f(a, b): return a + b graph = self.make_graphs(f, [5, 6])[0] regalloc = perform_register_allocation(graph, 'int') va, vb = graph.startblock.inputargs vc = graph.startblock.operations[0].result assert regalloc.getcolor(va) == 0 assert regalloc.getcolor(vb) == 1 assert regalloc.getcolor(vc) == 0