def test_regalloc_exitswitch_2(self): v1 = Variable(); v1.concretetype = rclass.CLASSTYPE v2 = Variable(); v2.concretetype = rclass.CLASSTYPE v3 = Variable(); v3.concretetype = rclass.CLASSTYPE v4 = Variable(); v4.concretetype = rclass.CLASSTYPE block = Block([]) block.operations = [ SpaceOperation('res_call', [], v1), SpaceOperation('-live-', [], None), ] graph = FunctionGraph('f', block, v4) exclink = Link([v2], graph.returnblock) exclink.llexitcase = 123 # normally an exception class exclink.last_exception = v2 exclink.last_exc_value = "unused" block.exitswitch = c_last_exception block.closeblock(Link([v1], graph.returnblock), exclink) # self.check_assembler(graph, """ res_call -> %i0 -live- catch_exception L1 int_return %i0 --- L1: goto_if_exception_mismatch $123, L2 last_exception -> %i0 int_return %i0 --- L2: reraise """)
def rewrite_can_enter_jit(self, jd, can_enter_jits): FUNCPTR = jd._PTR_JIT_ENTER_FUNCTYPE jit_enter_fnptr = self.helper_func(FUNCPTR, jd._maybe_enter_jit_fn) if len(can_enter_jits) == 0: # see test_warmspot.test_no_loop_at_all operations = jd.portal_graph.startblock.operations op1 = operations[0] assert (op1.opname == 'jit_marker' and op1.args[0].value == 'jit_merge_point') op0 = SpaceOperation('jit_marker', [Constant('can_enter_jit', lltype.Void)] + op1.args[1:], None) operations.insert(0, op0) can_enter_jits = [(jd.portal_graph, jd.portal_graph.startblock, 0)] for graph, block, index in can_enter_jits: if graph is jd._jit_merge_point_in: continue op = block.operations[index] greens_v, reds_v = support.decode_hp_hint_args(op) args_v = greens_v + reds_v vlist = [Constant(jit_enter_fnptr, FUNCPTR)] + args_v v_result = Variable() v_result.concretetype = lltype.Void newop = SpaceOperation('direct_call', vlist, v_result) block.operations[index] = newop
def test_regalloc_lists(self): v1 = Variable() v1.concretetype = lltype.Signed v2 = Variable() v2.concretetype = lltype.Signed v3 = Variable() v3.concretetype = lltype.Signed v4 = Variable() v4.concretetype = lltype.Signed v5 = Variable() v5.concretetype = lltype.Signed block = Block([v1]) block.operations = [ SpaceOperation('int_add', [v1, Constant(1, lltype.Signed)], v2), SpaceOperation('rescall', [ListOfKind('int', [v1, v2])], v5), SpaceOperation('rescall', [ListOfKind('int', [v1, v2])], v3), ] graph = FunctionGraph('f', block, v4) block.closeblock(Link([v3], graph.returnblock)) # self.check_assembler( graph, """ int_add %i0, $1 -> %i1 rescall I[%i0, %i1] -> %i2 rescall I[%i0, %i1] -> %i0 int_return %i0 """)
def fold_op_list(operations, constants, exit_early=False, exc_catch=False): newops = [] folded_count = 0 for spaceop in operations: vargsmodif = False vargs = [] args = [] for v in spaceop.args: if isinstance(v, Constant): args.append(v.value) elif v in constants: v = constants[v] vargsmodif = True args.append(v.value) vargs.append(v) try: op = getattr(llop, spaceop.opname) except AttributeError: pass else: if not op.sideeffects and len(args) == len(vargs): RESTYPE = spaceop.result.concretetype try: result = op(RESTYPE, *args) except TypeError: pass except (KeyboardInterrupt, SystemExit): raise except Exception: pass # turn off reporting these as warnings: useless #log.WARNING('constant-folding %r:' % (spaceop,)) #log.WARNING(' %s: %s' % (e.__class__.__name__, e)) else: # success in folding this space operation if spaceop.opname in fixup_op_result: result = fixup_op_result[spaceop.opname](result) constants[spaceop.result] = Constant(result, RESTYPE) folded_count += 1 continue # failed to fold an operation, exit early if requested if exit_early: return folded_count else: if vargsmodif: if (spaceop.opname == 'indirect_call' and isinstance(vargs[0], Constant)): spaceop = SpaceOperation('direct_call', vargs[:-1], spaceop.result) else: spaceop = SpaceOperation(spaceop.opname, vargs, spaceop.result) newops.append(spaceop) # end if exit_early: return folded_count else: return newops
def do_operation(self, name, *args_w): recorder = self.recorder if getattr(recorder, 'final_state', None) is not None: self.mergeblock(recorder.crnt_block, recorder.final_state) raise StopFlowing spaceop = SpaceOperation(name, args_w, Variable()) spaceop.offset = self.last_instr recorder.append(spaceop) return spaceop.result
def rename_op(op): args = [rename(a) for a in op.args] op = SpaceOperation(op.opname, args, rename(op.result), op.offset) # special case... if op.opname == 'indirect_call': if isinstance(op.args[0], Constant): assert isinstance(op.args[-1], Constant) del op.args[-1] op.opname = 'direct_call' return op
def create_proxy_graph(self, op): """ creates a graph which calls the original function, checks for raised exceptions, fetches and then raises them again. If this graph is inlined, the correct exception matching blocks are produced.""" # XXX slightly annoying: construct a graph by hand # but better than the alternative result = op.result.copy() opargs = [] inputargs = [] callargs = [] ARGTYPES = [] for var in op.args: if isinstance(var, Variable): v = Variable() v.concretetype = var.concretetype inputargs.append(v) opargs.append(v) callargs.append(var) ARGTYPES.append(var.concretetype) else: opargs.append(var) newop = SpaceOperation(op.opname, opargs, result) startblock = Block(inputargs) startblock.operations.append(newop) newgraph = FunctionGraph("dummy_exc1", startblock) startblock.closeblock(Link([result], newgraph.returnblock)) newgraph.returnblock.inputargs[0].concretetype = op.result.concretetype self.gen_exc_check(startblock, newgraph.returnblock) excblock = Block([]) llops = rtyper.LowLevelOpList(None) var_value = self.gen_getfield('exc_value', llops) var_type = self.gen_getfield('exc_type', llops) # c_check1 = self.c_assertion_error_ll_exc_type c_check2 = self.c_n_i_error_ll_exc_type llops.genop('debug_catch_exception', [var_type, c_check1, c_check2]) # self.gen_setfield('exc_value', self.c_null_evalue, llops) self.gen_setfield('exc_type', self.c_null_etype, llops) excblock.operations[:] = llops newgraph.exceptblock.inputargs[ 0].concretetype = self.lltype_of_exception_type newgraph.exceptblock.inputargs[ 1].concretetype = self.lltype_of_exception_value excblock.closeblock(Link([var_type, var_value], newgraph.exceptblock)) startblock.exits[True].target = excblock startblock.exits[True].args = [] fptr = self.constant_func("dummy_exc1", ARGTYPES, op.result.concretetype, newgraph) return newgraph, SpaceOperation("direct_call", [fptr] + callargs, op.result)
def handle_residual_call(self, op, newgraph, newnodes): fspecptr = getfunctionptr(newgraph) newargs = [Constant(fspecptr, concretetype=lltype.typeOf(fspecptr))] newargs += self.expand_nodes(newnodes) newresult = self.make_rt_result(op.result) newop = SpaceOperation('direct_call', newargs, newresult) return [newop]
def handle_unreachable(self, op): from rpython.rtyper.lltypesystem.rstr import string_repr msg = 'unreachable: %s' % (op, ) ll_msg = string_repr.convert_const(msg) c_msg = Constant(ll_msg, lltype.typeOf(ll_msg)) newresult = self.make_rt_result(op.result) return [SpaceOperation('debug_fatalerror', [c_msg], newresult)]
def call_final_function(translator, final_func, annhelper=None): """When the program finishes normally, call 'final_func()'.""" from rpython.annotator import model as annmodel from rpython.rtyper.lltypesystem import lltype from rpython.rtyper.annlowlevel import MixLevelHelperAnnotator own_annhelper = (annhelper is None) if own_annhelper: annhelper = MixLevelHelperAnnotator(translator.rtyper) c_final_func = annhelper.constfunc(final_func, [], annmodel.s_None) if own_annhelper: annhelper.finish() entry_point = translator.entry_point_graph v = entry_point.getreturnvar().copy() extrablock = Block([v]) v_none = varoftype(lltype.Void) newop = SpaceOperation('direct_call', [c_final_func], v_none) extrablock.operations = [newop] extrablock.closeblock(Link([v], entry_point.returnblock)) for block in entry_point.iterblocks(): if block is not extrablock: for link in block.exits: if link.target is entry_point.returnblock: link.target = extrablock checkgraph(entry_point)
def test_decode_builtin_call_method(): A = lltype.GcArray(lltype.Signed) def myfoobar(a, i, marker, c): assert marker == 'mymarker' return a[i] * ord(c) myfoobar.oopspec = 'spam.foobar(a, 2, c, i)' TYPE = lltype.FuncType( [lltype.Ptr(A), lltype.Signed, lltype.Void, lltype.Char], lltype.Signed) fnobj = lltype.functionptr(TYPE, 'foobar', _callable=myfoobar) vi = Variable('i') vi.concretetype = lltype.Signed vc = Variable('c') vc.concretetype = lltype.Char v_result = Variable('result') v_result.concretetype = lltype.Signed myarray = lltype.malloc(A, 10) myarray[5] = 42 op = SpaceOperation( 'direct_call', [newconst(fnobj), newconst(myarray), vi, voidconst('mymarker'), vc], v_result) oopspec, opargs = decode_builtin_call(op) assert oopspec == 'spam.foobar' assert opargs == [newconst(myarray), newconst(2), vc, vi]
def test_func_simple(): # -------------------- flowgraph building -------------------- # def f(x): # return x+1 x = Variable("x") x.concretetype = Signed result = Variable("result") result.concretetype = Signed one = Constant(1) one.concretetype = Signed op = SpaceOperation("int_add", [x, one], result) block = Block([x]) graph = FunctionGraph("f", block) block.operations.append(op) block.closeblock(Link([result], graph.returnblock)) graph.getreturnvar().concretetype = Signed # -------------------- end -------------------- F = FuncType([Signed], Signed) f = functionptr(F, "f", graph=graph) db = LowLevelDatabase() db.get(f) db.complete() dump_on_stdout(db) S = GcStruct('testing', ('fptr', Ptr(F))) s = malloc(S) s.fptr = f db = LowLevelDatabase() db.get(s) db.complete() dump_on_stdout(db)
def instrument_inline_candidates(graphs, threshold): cache = {None: False} def candidate(graph): try: return cache[graph] except KeyError: res = static_instruction_count(graph) <= threshold cache[graph] = res return res n = 0 for parentgraph in graphs: for block in parentgraph.iterblocks(): ops = block.operations i = len(ops) - 1 while i >= 0: op = ops[i] i -= 1 if op.opname == "direct_call": funcobj = op.args[0].value._obj graph = getattr(funcobj, 'graph', None) if graph is not None: if getattr(getattr(funcobj, '_callable', None), '_dont_inline_', False): continue if candidate(graph): tag = Constant('inline', Void) label = Constant(n, Signed) dummy = Variable() dummy.concretetype = Void count = SpaceOperation('instrument_count', [tag, label], dummy) ops.insert(i + 1, count) n += 1 log.inlining("%d call sites instrumented" % n)
def test_SSA_to_SSI(): c = Variable('c') x = Variable('x') y = Variable('y') b1 = Block([c]) b2 = Block([x]) b3 = Block([]) graph = FunctionGraph('x', b1) b2.operations.append(SpaceOperation('add', [x, c], y)) b2.exitswitch = y b1.closeblock(Link([Constant(0)], b2)) b2.closeblock(Link([y], b2), Link([], b3)) b3.closeblock(Link([y, c], graph.exceptblock)) SSA_to_SSI(graph) assert len(b1.inputargs) == 1 assert len(b2.inputargs) == 2 assert len(b3.inputargs) == 2 assert b2.inputargs == b2.operations[0].args assert len(b1.exits[0].args) == 2 assert b1.exits[0].args[1] is c assert len(b2.exits[0].args) == 2 assert b2.exits[0].args == [y, b2.inputargs[1]] assert len(b2.exits[1].args) == 2 assert len(b3.exits[0].args) == 2 index = b3.inputargs.index(b3.exits[0].args[0]) assert b2.exits[1].args[index] is b2.operations[0].result index = b3.inputargs.index(b3.exits[0].args[1]) assert b2.exits[1].args[index] is b2.inputargs[1]
def builtin_test(oopspec_name, args, RESTYPE, expected): v_result = varoftype(RESTYPE) tr = Transformer(FakeCPU(), FakeCallControl()) tr.immutable_arrays = {} tr.vable_array_vars = {} if '/' in oopspec_name: oopspec_name, property = oopspec_name.split('/') def force_flags(op): if property == 'NONNEG': return True if property == 'NEG': return False raise ValueError(property) tr._get_list_nonneg_canraise_flags = force_flags op = SpaceOperation('direct_call', [Constant("myfunc", lltype.Void)] + args, v_result) try: oplist = tr._handle_list_call(op, oopspec_name, args) except NotSupported: assert expected is NotSupported else: assert expected is not NotSupported assert oplist is not None flattener = GraphFlattener(None, fake_regallocs()) if not isinstance(oplist, list): oplist = [oplist] for op1 in oplist: flattener.serialize_op(op1) assert_format(flattener.ssarepr, expected)
def dispatcher(self, shape, index, argtypes, resulttype): key = shape, index, tuple(argtypes), resulttype if key in self._dispatch_cache: return self._dispatch_cache[key] from rpython.translator.unsimplify import varoftype from rpython.flowspace.model import FunctionGraph, Link, Block, SpaceOperation inputargs = [varoftype(t) for t in [Char] + argtypes] startblock = Block(inputargs) startblock.exitswitch = inputargs[0] graph = FunctionGraph("dispatcher", startblock, varoftype(resulttype)) row_of_graphs = self.callfamily.calltables[shape][index] links = [] descs = list(self.s_pbc.descriptions) if self.s_pbc.can_be_None: descs.insert(0, None) for desc in descs: if desc is None: continue args_v = [varoftype(t) for t in argtypes] b = Block(args_v) llfn = self.rtyper.getcallable(row_of_graphs[desc]) v_fn = inputconst(typeOf(llfn), llfn) v_result = varoftype(resulttype) b.operations.append( SpaceOperation("direct_call", [v_fn] + args_v, v_result)) b.closeblock(Link([v_result], graph.returnblock)) i = self.descriptions.index(desc) links.append(Link(inputargs[1:], b, chr(i))) links[-1].llexitcase = chr(i) startblock.closeblock(*links) self.rtyper.annotator.translator.graphs.append(graph) ll_ret = getfunctionptr(graph) #FTYPE = FuncType c_ret = self._dispatch_cache[key] = inputconst(typeOf(ll_ret), ll_ret) return c_ret
def do_check(self, opname, oopspecindex, ARGS, RESULT): vlist = [varoftype(ARG) for ARG in ARGS] v_result = varoftype(RESULT) op = SpaceOperation(opname, vlist, v_result) tr = Transformer(FakeCPU(), FakeBuiltinCallControl()) op1 = tr.rewrite_operation(op) if isinstance(op1, list): [op1] = op1 # def is_llf(TYPE): return (TYPE == lltype.SignedLongLong or TYPE == lltype.UnsignedLongLong or TYPE == lltype.Float) if is_llf(RESULT): assert op1.opname == 'residual_call_irf_f' else: assert op1.opname == 'residual_call_irf_i' gotindex = getattr(EffectInfo, 'OS_' + op1.args[0].value.upper().lstrip('U')) assert gotindex == oopspecindex assert list( op1.args[1]) == [v for v in vlist if not is_llf(v.concretetype)] assert list(op1.args[2]) == [] assert list( op1.args[3]) == [v for v in vlist if is_llf(v.concretetype)] assert op1.args[4] == 'calldescr-%d' % oopspecindex assert op1.result == v_result
def test_is_true(self): for opname, T in [('llong_is_true', lltype.SignedLongLong), ('ullong_is_true', lltype.UnsignedLongLong)]: v = varoftype(T) v_result = varoftype(lltype.Bool) op = SpaceOperation(opname, [v], v_result) tr = Transformer(FakeCPU(), FakeBuiltinCallControl()) oplist = tr.rewrite_operation(op) assert len(oplist) == 2 assert oplist[0].opname == 'residual_call_irf_f' assert oplist[0].args[0].value == opname.split( '_')[0] + '_from_int' assert list(oplist[0].args[1]) == [const(0)] assert list(oplist[0].args[2]) == [] assert list(oplist[0].args[3]) == [] assert oplist[0].args[4] == 'calldescr-84' v_x = oplist[0].result assert isinstance(v_x, Variable) assert v_x.concretetype is T assert oplist[1].opname == 'residual_call_irf_i' assert oplist[1].args[0].value == 'llong_ne' assert list(oplist[1].args[1]) == [] assert list(oplist[1].args[2]) == [] assert list(oplist[1].args[3]) == [v, v_x] assert oplist[1].args[4] == 'calldescr-76' assert oplist[1].result == v_result
def make_dispatcher(self, shape, index, argtypes, resulttype): inputargs = [varoftype(t) for t in [Char] + argtypes] startblock = Block(inputargs) startblock.exitswitch = inputargs[0] graph = FunctionGraph("dispatcher", startblock, varoftype(resulttype)) row_of_graphs = self.callfamily.calltables[shape][index] links = [] descs = list(self.s_pbc.descriptions) if self.s_pbc.can_be_None: descs.insert(0, None) for desc in descs: if desc is None: continue args_v = [varoftype(t) for t in argtypes] b = Block(args_v) llfn = self.rtyper.getcallable(row_of_graphs[desc]) v_fn = inputconst(typeOf(llfn), llfn) v_result = varoftype(resulttype) b.operations.append( SpaceOperation("direct_call", [v_fn] + args_v, v_result)) b.closeblock(Link([v_result], graph.returnblock)) i = self.descriptions.index(desc) links.append(Link(inputargs[1:], b, chr(i))) links[-1].llexitcase = chr(i) startblock.closeblock(*links) return graph
def materialize_object(obj_key, state, ops): """ Accepts a VirtualState object and creates the required operations, for its materialization/initialization. XXX: Edits ops in-place """ if obj_key not in state: return False # We're gonna delete the object from the state dict first (since it has # escaped) for correct recursion reasons in case of cyclic dependency. # this needs to be done with all the aliases of the object! vo = state[obj_key] # Thus, we'll make a copy first. assert obj_key in vo.aliases for key in vo.aliases: del state[key] # Starting assembling the operations. Creation and required castings: newvar = Variable() newvar.concretetype = vo.concretetype ops.append(SpaceOperation('malloc', vo.malloc_args, newvar)) # recreate the aliases for var in vo.aliases: if var.concretetype != vo.concretetype: ops.append(SpaceOperation('cast_pointer', [newvar], var)) else: ops.append(SpaceOperation('same_as', [newvar], var)) # Initialization for (key, concretetype), value in vo.vars.items(): if concretetype != vo.concretetype: # we need a cast_pointer v = Variable() v.concretetype = concretetype op = SpaceOperation('cast_pointer', [newvar], v) ops.append(op) target = v else: target = newvar # What if the assigned is a virtual object? Recursion: materialize_object(value, state, ops) m = Variable() m.concretetype = lltype.Void ops.append(SpaceOperation('setfield', [target, Constant(key, lltype.Void), value], m)) return True
def test_write_barrier_support_setarrayitem(): PTR_TYPE2 = lltype.Ptr(lltype.GcStruct('T', ('y', lltype.Signed))) ARRAYPTR = lltype.Ptr(lltype.GcArray(PTR_TYPE2)) write_barrier_check(SpaceOperation( "setarrayitem", [varoftype(ARRAYPTR), varoftype(lltype.Signed), varoftype(PTR_TYPE2)], varoftype(lltype.Void)))
def test_dont_add_write_barrier_for_constant_new_value(): PTR_TYPE2 = lltype.Ptr(lltype.GcStruct('T', ('y', lltype.Signed))) PTR_TYPE = lltype.Ptr(lltype.GcStruct('S', ('x', PTR_TYPE2))) write_barrier_check(SpaceOperation( "setfield", [varoftype(PTR_TYPE), Constant('x', lltype.Void), Constant('foo', varoftype(PTR_TYPE2))], varoftype(lltype.Void)), needs_write_barrier=False)
def test_write_barrier_support_setfield(): PTR_TYPE2 = lltype.Ptr(lltype.GcStruct('T', ('y', lltype.Signed))) PTR_TYPE = lltype.Ptr(lltype.GcStruct('S', ('x', PTR_TYPE2))) write_barrier_check(SpaceOperation( "setfield", [varoftype(PTR_TYPE), Constant('x', lltype.Void), varoftype(PTR_TYPE2)], varoftype(lltype.Void)))
def genop(self, opname, args, resulttype=None, resultvar=None): assert resulttype is None or resultvar is None if resultvar is None: return self.llops.genop(opname, args, resulttype=resulttype) else: newop = SpaceOperation(opname, args, resultvar) self.llops.append(newop) return resultvar
def handle_op_indirect_call(self, op): v_func = self.rename_nonvirtual(op.args[0], op) if isinstance(v_func, Constant): op = SpaceOperation('direct_call', [v_func] + op.args[1:-1], op.result) return self.handle_op_direct_call(op) else: return self.handle_default(op)
def test_write_barrier_support_setinteriorfield(): PTR_TYPE2 = lltype.Ptr(lltype.GcStruct('T', ('y', lltype.Signed))) ARRAYPTR2 = lltype.Ptr(lltype.GcArray(('a', lltype.Signed), ('b', PTR_TYPE2))) write_barrier_check(SpaceOperation( "setinteriorfield", [varoftype(ARRAYPTR2), varoftype(lltype.Signed), Constant('b', lltype.Void), varoftype(PTR_TYPE2)], varoftype(lltype.Void)))
def insert_along_link(link, opname, args, cache): b2 = link.target if b2 not in cache: newblock = Block([v.copy() for v in b2.inputargs]) newblock.operations.append( SpaceOperation(opname, args, varoftype(lltype.Void))) newblock.closeblock(Link(list(newblock.inputargs), b2)) cache[b2] = newblock link.target = cache[b2]
def test_null_fnptr(): from rpython.flowspace.model import SpaceOperation, Constant from rpython.rtyper.lltypesystem.lltype import Void, FuncType, nullptr from rpython.translator.translator import TranslationContext t = TranslationContext() fnptr = nullptr(FuncType([], Void)) op = SpaceOperation('direct_call', [Constant(fnptr)], None) analyzer = BoolGraphAnalyzer(t) assert not analyzer.analyze(op)
def _fix_graph_after_inlining(graph, initial_block, initial_index): op = initial_block.operations.pop(initial_index) assert op.opname == 'gc_push_roots' seen = set() pending = [(initial_block, initial_index, op.args)] while pending: block, start_index, track_args = pending.pop() if block in seen: continue seen.add(block) assert block.operations != () # did not find the gc_pop_roots? new_operations = block.operations[:start_index] stop = False for i in range(start_index, len(block.operations)): op = block.operations[i] if op.opname == 'gc_push_roots': raise Exception("%r: seems to have inlined inside it another " "graph which also uses GC roots" % (graph,)) if op.opname == 'gc_pop_roots': # end of the inlined graph, drop gc_pop_roots, keep the tail new_operations += block.operations[i + 1:] stop = True break if op.opname in ('direct_call', 'indirect_call'): new_operations.append(SpaceOperation('gc_push_roots', track_args[:], varoftype(lltype.Void))) new_operations.append(op) new_operations.append(SpaceOperation('gc_pop_roots', track_args[:], varoftype(lltype.Void))) else: new_operations.append(op) block.operations = new_operations if not stop: for link in block.exits: track_next = [] for v in track_args: if not isinstance(v, Variable): continue i = link.args.index(v) # should really be here w = link.target.inputargs[i] track_next.append(w) pending.append((link.target, 0, track_next))
def test_descr(self): class FooDescr(AbstractDescr): def __repr__(self): return 'hi_there!' op = SpaceOperation('foobar', [FooDescr()], None) flattener = GraphFlattener(None, fake_regallocs()) flattener.serialize_op(op) assert_format(flattener.ssarepr, """ foobar hi_there! """)
def test_graphs_from_no_target(): cc = CallControl() F = lltype.FuncType([], lltype.Signed) v = varoftype(lltype.Signed) op = SpaceOperation( 'indirect_call', [varoftype(lltype.Ptr(F)), Constant(None, lltype.Void)], v) lst = cc.graphs_from(op, {}.__contains__) assert lst is None
def handle_default(self, op): newargs = [self.rename_nonvirtual(v, op) for v in op.args] constresult = try_fold_operation(op.opname, newargs, op.result.concretetype) if constresult: self.make_const_rt_result(op.result, constresult[0]) return [] else: newresult = self.make_rt_result(op.result) return [SpaceOperation(op.opname, newargs, newresult)]