def unformat_arg(s): if s.endswith(','): s = s[:-1].rstrip() if s[0] == '%': try: return registers[s] except KeyError: num = int(s[2:]) if s[1] == 'i': reg = Register('int', num) elif s[1] == 'r': reg = Register('ref', num) elif s[1] == 'f': reg = Register('float', num) else: raise AssertionError("bad register type") registers[s] = reg return reg elif s[0] == '$': intvalue = int(s[1:]) return Constant(intvalue, lltype.Signed) elif s[0] == 'L': return TLabel(s) elif s[0] in 'IRF' and s[1] == '[' and s[-1] == ']': items = split_words(s[2:-1]) items = map(unformat_arg, items) return ListOfKind({'I': 'int', 'R': 'ref', 'F': 'float'}[s[0]], items) elif s.startswith('<SwitchDictDescr '): assert s.endswith('>') switchdict = SwitchDictDescr() switchdict._labels = [] items = split_words(s[len('<SwitchDictDescr '):-1]) for item in items: key, value = item.split(':') value = value.rstrip(',') switchdict._labels.append((int(key), TLabel(value))) return switchdict else: raise AssertionError("unsupported argument: %r" % (s,))
def insert_exits(self, block): if len(block.exits) == 1: # A single link, fall-through link = block.exits[0] assert link.exitcase in (None, False, True) # the cases False or True should not really occur, but can show # up in the manually hacked graphs for generators... self.make_link(link) # elif block.exitswitch is c_last_exception: # An exception block. See test_exc_exitswitch in test_flatten.py # for an example of what kind of code this makes. index = -1 while True: lastopname = block.operations[index].opname if lastopname != '-live-': break index -= 1 assert block.exits[0].exitcase is None # is this always True? # if not self._include_all_exc_links: if index == -1: # cannot raise: the last instruction is not # actually a '-live-' self.make_link(block.exits[0]) return # self.emitline('catch_exception', TLabel(block.exits[0])) self.make_link(block.exits[0]) self.emitline(Label(block.exits[0])) for link in block.exits[1:]: if (link.exitcase is Exception or (link.exitcase is OverflowError and lastopname.startswith('int_') and lastopname.endswith('_ovf'))): # this link captures all exceptions self.make_exception_link(link) break self.emitline( 'goto_if_exception_mismatch', Constant(link.llexitcase, lltype.typeOf(link.llexitcase)), TLabel(link)) self.make_exception_link(link) self.emitline(Label(link)) else: # no link captures all exceptions, so we have to put a reraise # for the other exceptions self.emitline("reraise") self.emitline("---") # elif len(block.exits) == 2 and (isinstance(block.exitswitch, tuple) or block.exitswitch.concretetype == lltype.Bool): # Two exit links with a boolean condition linkfalse, linktrue = block.exits if linkfalse.llexitcase == True: linkfalse, linktrue = linktrue, linkfalse opname = 'goto_if_not' livebefore = False if isinstance(block.exitswitch, tuple): # special case produced by jtransform.optimize_goto_if_not() opname = 'goto_if_not_' + block.exitswitch[0] opargs = block.exitswitch[1:] if opargs[-1] == '-live-before': livebefore = True opargs = opargs[:-1] else: assert block.exitswitch.concretetype == lltype.Bool opargs = [block.exitswitch] # lst = self.flatten_list(opargs) + [TLabel(linkfalse)] if livebefore: self.emitline('-live-') self.emitline(opname, *lst) if not livebefore: self.emitline('-live-', TLabel(linkfalse)) # true path: self.make_link(linktrue) # false path: self.emitline(Label(linkfalse)) self.make_link(linkfalse) # else: # A switch. # switches = [ link for link in block.exits if link.exitcase != 'default' ] switches.sort(key=lambda link: link.llexitcase) kind = getkind(block.exitswitch.concretetype) assert kind == 'int' # XXX # # A switch on an integer, implementable efficiently with the # help of a SwitchDictDescr. We use this even if there are # very few cases: in pyjitpl.py, opimpl_switch() will promote # the int only if it matches one of the cases. from rpython.jit.codewriter.jitcode import SwitchDictDescr switchdict = SwitchDictDescr() switchdict._labels = [] self.emitline('-live-') # for 'guard_value' self.emitline('switch', self.getcolor(block.exitswitch), switchdict) # emit the default path if block.exits[-1].exitcase == 'default': self.make_link(block.exits[-1]) else: self.emitline("unreachable") self.emitline("---") # for switch in switches: key = lltype.cast_primitive(lltype.Signed, switch.llexitcase) switchdict._labels.append((key, TLabel(switch))) # emit code for that path # note: we need a -live- for all the 'guard_false' we produce # if the switched value doesn't match any case. self.emitline(Label(switch)) self.emitline('-live-') self.make_link(switch)
def insert_exits(self, block): if len(block.exits) == 1: # A single link, fall-through link = block.exits[0] assert link.exitcase in (None, False, True) # the cases False or True should not really occur, but can show # up in the manually hacked graphs for generators... self.make_link(link) # elif block.canraise: # An exception block. See test_exc_exitswitch in test_flatten.py # for an example of what kind of code this makes. index = -1 while True: lastopname = block.operations[index].opname if lastopname != '-live-': break index -= 1 assert block.exits[0].exitcase is None # is this always True? # if not self._include_all_exc_links: if index == -1: # cannot raise: the last instruction is not # actually a '-live-' self.make_link(block.exits[0]) return # self.emitline('catch_exception', TLabel(block.exits[0])) self.make_link(block.exits[0]) self.emitline(Label(block.exits[0])) for link in block.exits[1:]: if (link.exitcase is Exception or (link.exitcase is OverflowError and lastopname.startswith('int_') and lastopname.endswith('_ovf'))): # this link captures all exceptions self.make_exception_link(link) break self.emitline('goto_if_exception_mismatch', Constant(link.llexitcase, lltype.typeOf(link.llexitcase)), TLabel(link)) self.make_exception_link(link) self.emitline(Label(link)) else: # no link captures all exceptions, so we have to put a reraise # for the other exceptions self.emitline("reraise") self.emitline("---") # elif len(block.exits) == 2 and ( isinstance(block.exitswitch, tuple) or block.exitswitch.concretetype == lltype.Bool): # Two exit links with a boolean condition linkfalse, linktrue = block.exits if linkfalse.llexitcase == True: linkfalse, linktrue = linktrue, linkfalse opname = 'goto_if_not' livebefore = False if isinstance(block.exitswitch, tuple): # special case produced by jtransform.optimize_goto_if_not() opname = 'goto_if_not_' + block.exitswitch[0] opargs = block.exitswitch[1:] if opargs[-1] == '-live-before': livebefore = True opargs = opargs[:-1] else: assert block.exitswitch.concretetype == lltype.Bool opargs = [block.exitswitch] # lst = self.flatten_list(opargs) + [TLabel(linkfalse)] if livebefore: self.emitline('-live-') self.emitline(opname, *lst) if not livebefore: self.emitline('-live-', TLabel(linkfalse)) # true path: self.make_link(linktrue) # false path: self.emitline(Label(linkfalse)) self.make_link(linkfalse) # else: # A switch. # switches = [link for link in block.exits if link.exitcase != 'default'] switches.sort(key=lambda link: link.llexitcase) kind = getkind(block.exitswitch.concretetype) assert kind == 'int' # XXX # # A switch on an integer, implementable efficiently with the # help of a SwitchDictDescr. We use this even if there are # very few cases: in pyjitpl.py, opimpl_switch() will promote # the int only if it matches one of the cases. from rpython.jit.codewriter.jitcode import SwitchDictDescr switchdict = SwitchDictDescr() switchdict._labels = [] self.emitline('-live-') # for 'guard_value' self.emitline('switch', self.getcolor(block.exitswitch), switchdict) # emit the default path if block.exits[-1].exitcase == 'default': self.make_link(block.exits[-1]) else: self.emitline("unreachable") self.emitline("---") # for switch in switches: key = lltype.cast_primitive(lltype.Signed, switch.llexitcase) switchdict._labels.append((key, TLabel(switch))) # emit code for that path # note: we need a -live- for all the 'guard_false' we produce # if the switched value doesn't match any case. self.emitline(Label(switch)) self.emitline('-live-') self.make_link(switch)