PageRenderTime 94ms CodeModel.GetById 16ms app.highlight 64ms RepoModel.GetById 1ms app.codeStats 1ms

/pypy/jit/codewriter/jtransform.py

http://github.com/pypy/pypy
Python | 1758 lines | 1651 code | 57 blank | 50 comment | 87 complexity | 3d02cf1626a2333d8a8d6170508e5161 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1import py
   2
   3from pypy.jit.codewriter import support, heaptracker, longlong
   4from pypy.jit.codewriter.effectinfo import EffectInfo
   5from pypy.jit.codewriter.flatten import ListOfKind, IndirectCallTargets
   6from pypy.jit.codewriter.policy import log
   7from pypy.jit.metainterp import quasiimmut
   8from pypy.jit.metainterp.history import getkind
   9from pypy.jit.metainterp.typesystem import deref, arrayItem
  10from pypy.jit.metainterp.blackhole import BlackholeInterpreter
  11from pypy.objspace.flow.model import SpaceOperation, Variable, Constant, c_last_exception
  12from pypy.rlib import objectmodel
  13from pypy.rlib.jit import _we_are_jitted
  14from pypy.rpython.lltypesystem import lltype, llmemory, rstr, rclass, rffi
  15from pypy.rpython.rclass import IR_QUASIIMMUTABLE, IR_QUASIIMMUTABLE_ARRAY
  16from pypy.translator.simplify import get_funcobj
  17from pypy.translator.unsimplify import varoftype
  18
  19class UnsupportedMallocFlags(Exception):
  20    pass
  21
  22def transform_graph(graph, cpu=None, callcontrol=None, portal_jd=None):
  23    """Transform a control flow graph to make it suitable for
  24    being flattened in a JitCode.
  25    """
  26    t = Transformer(cpu, callcontrol, portal_jd)
  27    t.transform(graph)
  28
  29def integer_bounds(size, unsigned):
  30    if unsigned:
  31        return 0, 1 << (8 * size)
  32    else:
  33        return -(1 << (8 * size - 1)), 1 << (8 * size - 1)
  34
  35class Transformer(object):
  36    vable_array_vars = None
  37
  38    def __init__(self, cpu=None, callcontrol=None, portal_jd=None):
  39        self.cpu = cpu
  40        self.callcontrol = callcontrol
  41        self.portal_jd = portal_jd   # non-None only for the portal graph(s)
  42
  43    def transform(self, graph):
  44        self.graph = graph
  45        for block in list(graph.iterblocks()):
  46            self.optimize_block(block)
  47
  48    def optimize_block(self, block):
  49        if block.operations == ():
  50            return
  51        self.vable_array_vars = {}
  52        self.vable_flags = {}
  53        renamings = {}
  54        renamings_constants = {}    # subset of 'renamings', {Var:Const} only
  55        newoperations = []
  56        #
  57        def do_rename(var, var_or_const):
  58            if var.concretetype is lltype.Void:
  59                renamings[var] = Constant(None, lltype.Void)
  60                return
  61            renamings[var] = var_or_const
  62            if isinstance(var_or_const, Constant):
  63                value = var_or_const.value
  64                value = lltype._cast_whatever(var.concretetype, value)
  65                renamings_constants[var] = Constant(value, var.concretetype)
  66        #
  67        for op in block.operations:
  68            if renamings_constants:
  69                op = self._do_renaming(renamings_constants, op)
  70            oplist = self.rewrite_operation(op)
  71            #
  72            count_before_last_operation = len(newoperations)
  73            if not isinstance(oplist, list):
  74                oplist = [oplist]
  75            for op1 in oplist:
  76                if isinstance(op1, SpaceOperation):
  77                    newoperations.append(self._do_renaming(renamings, op1))
  78                elif op1 is None:
  79                    # rewrite_operation() returns None to mean "has no real
  80                    # effect, the result should just be renamed to args[0]"
  81                    if op.result is not None:
  82                        do_rename(op.result, renamings.get(op.args[0],
  83                                                           op.args[0]))
  84                elif isinstance(op1, Constant):
  85                    do_rename(op.result, op1)
  86                else:
  87                    raise TypeError(repr(op1))
  88        #
  89        if block.exitswitch == c_last_exception:
  90            if len(newoperations) == count_before_last_operation:
  91                self._killed_exception_raising_operation(block)
  92        block.operations = newoperations
  93        block.exitswitch = renamings.get(block.exitswitch, block.exitswitch)
  94        self.follow_constant_exit(block)
  95        self.optimize_goto_if_not(block)
  96        for link in block.exits:
  97            self._check_no_vable_array(link.args)
  98            self._do_renaming_on_link(renamings, link)
  99
 100    def _do_renaming(self, rename, op):
 101        op = SpaceOperation(op.opname, op.args[:], op.result)
 102        for i, v in enumerate(op.args):
 103            if isinstance(v, Variable):
 104                if v in rename:
 105                    op.args[i] = rename[v]
 106            elif isinstance(v, ListOfKind):
 107                newlst = []
 108                for x in v:
 109                    if x in rename:
 110                        x = rename[x]
 111                    newlst.append(x)
 112                op.args[i] = ListOfKind(v.kind, newlst)
 113        return op
 114
 115    def _check_no_vable_array(self, list):
 116        if not self.vable_array_vars:
 117            return
 118        for v in list:
 119            if v in self.vable_array_vars:
 120                raise AssertionError(
 121                    "A virtualizable array is passed around; it should\n"
 122                    "only be used immediately after being read.  Note\n"
 123                    "that a possible cause is indexing with an index not\n"
 124                    "known non-negative, or catching IndexError, or\n"
 125                    "not inlining at all (for tests: use listops=True).\n"
 126                    "Occurred in: %r" % self.graph)
 127            # extra explanation: with the way things are organized in
 128            # rpython/rlist.py, the ll_getitem becomes a function call
 129            # that is typically meant to be inlined by the JIT, but
 130            # this does not work with vable arrays because
 131            # jtransform.py expects the getfield and the getarrayitem
 132            # to be in the same basic block.  It works a bit as a hack
 133            # for simple cases where we performed the backendopt
 134            # inlining before (even with a very low threshold, because
 135            # there is _always_inline_ on the relevant functions).
 136
 137    def _do_renaming_on_link(self, rename, link):
 138        for i, v in enumerate(link.args):
 139            if isinstance(v, Variable):
 140                if v in rename:
 141                    link.args[i] = rename[v]
 142
 143    def _killed_exception_raising_operation(self, block):
 144        assert block.exits[0].exitcase is None
 145        block.exits = block.exits[:1]
 146        block.exitswitch = None
 147
 148    # ----------
 149
 150    def follow_constant_exit(self, block):
 151        v = block.exitswitch
 152        if isinstance(v, Constant) and v != c_last_exception:
 153            llvalue = v.value
 154            for link in block.exits:
 155                if link.llexitcase == llvalue:
 156                    break
 157            else:
 158                assert link.exitcase == 'default'
 159            block.exitswitch = None
 160            link.exitcase = link.llexitcase = None
 161            block.recloseblock(link)
 162
 163    def optimize_goto_if_not(self, block):
 164        """Replace code like 'v = int_gt(x,y); exitswitch = v'
 165           with just 'exitswitch = ('int_gt',x,y)'."""
 166        if len(block.exits) != 2:
 167            return False
 168        v = block.exitswitch
 169        if (v == c_last_exception or isinstance(v, tuple)
 170            or v.concretetype != lltype.Bool):
 171            return False
 172        for op in block.operations[::-1]:
 173            if v in op.args:
 174                return False   # variable is also used in cur block
 175            if v is op.result:
 176                if op.opname not in ('int_lt', 'int_le', 'int_eq', 'int_ne',
 177                                     'int_gt', 'int_ge',
 178                                     'int_is_zero', 'int_is_true',
 179                                     'ptr_eq', 'ptr_ne',
 180                                     'ptr_iszero', 'ptr_nonzero'):
 181                    return False    # not a supported operation
 182                # ok! optimize this case
 183                block.operations.remove(op)
 184                block.exitswitch = (op.opname,) + tuple(op.args)
 185                if op.opname in ('ptr_iszero', 'ptr_nonzero'):
 186                    block.exitswitch += ('-live-before',)
 187                # if the variable escape to the next block along a link,
 188                # replace it with a constant, because we know its value
 189                for link in block.exits:
 190                    while v in link.args:
 191                        index = link.args.index(v)
 192                        link.args[index] = Constant(link.llexitcase,
 193                                                    lltype.Bool)
 194                return True
 195        return False
 196
 197    # ----------
 198
 199    def rewrite_operation(self, op):
 200        try:
 201            rewrite = _rewrite_ops[op.opname]
 202        except KeyError:
 203            raise Exception("the JIT doesn't support the operation %r"
 204                            " in %r" % (op, getattr(self, 'graph', '?')))
 205        return rewrite(self, op)
 206
 207    def rewrite_op_same_as(self, op):
 208        if op.args[0] in self.vable_array_vars:
 209            self.vable_array_vars[op.result]= self.vable_array_vars[op.args[0]]
 210
 211    def rewrite_op_cast_pointer(self, op):
 212        newop = self.rewrite_op_same_as(op)
 213        assert newop is None
 214        return
 215        # disabled for now
 216        if (self._is_rclass_instance(op.args[0]) and
 217                self._is_rclass_instance(op.result)):
 218            FROM = op.args[0].concretetype.TO
 219            TO = op.result.concretetype.TO
 220            if lltype._castdepth(TO, FROM) > 0:
 221                vtable = heaptracker.get_vtable_for_gcstruct(self.cpu, TO)
 222                const_vtable = Constant(vtable, lltype.typeOf(vtable))
 223                return [None, # hack, do the right renaming from op.args[0] to op.result
 224                        SpaceOperation("record_known_class", [op.args[0], const_vtable], None)]
 225
 226    def rewrite_op_jit_record_known_class(self, op):
 227        return SpaceOperation("record_known_class", [op.args[0], op.args[1]], None)
 228
 229    def rewrite_op_cast_bool_to_int(self, op): pass
 230    def rewrite_op_cast_bool_to_uint(self, op): pass
 231    def rewrite_op_cast_char_to_int(self, op): pass
 232    def rewrite_op_cast_unichar_to_int(self, op): pass
 233    def rewrite_op_cast_int_to_char(self, op): pass
 234    def rewrite_op_cast_int_to_unichar(self, op): pass
 235    def rewrite_op_cast_int_to_uint(self, op): pass
 236    def rewrite_op_cast_uint_to_int(self, op): pass
 237
 238    def _rewrite_symmetric(self, op):
 239        """Rewrite 'c1+v2' into 'v2+c1' in an attempt to avoid generating
 240        too many variants of the bytecode."""
 241        if (isinstance(op.args[0], Constant) and
 242            isinstance(op.args[1], Variable)):
 243            reversename = {'int_lt': 'int_gt',
 244                           'int_le': 'int_ge',
 245                           'int_gt': 'int_lt',
 246                           'int_ge': 'int_le',
 247                           'uint_lt': 'uint_gt',
 248                           'uint_le': 'uint_ge',
 249                           'uint_gt': 'uint_lt',
 250                           'uint_ge': 'uint_le',
 251                           'float_lt': 'float_gt',
 252                           'float_le': 'float_ge',
 253                           'float_gt': 'float_lt',
 254                           'float_ge': 'float_le',
 255                           }.get(op.opname, op.opname)
 256            return SpaceOperation(reversename,
 257                                  [op.args[1], op.args[0]] + op.args[2:],
 258                                  op.result)
 259        else:
 260            return op
 261
 262    rewrite_op_int_add = _rewrite_symmetric
 263    rewrite_op_int_mul = _rewrite_symmetric
 264    rewrite_op_int_and = _rewrite_symmetric
 265    rewrite_op_int_or  = _rewrite_symmetric
 266    rewrite_op_int_xor = _rewrite_symmetric
 267    rewrite_op_int_lt  = _rewrite_symmetric
 268    rewrite_op_int_le  = _rewrite_symmetric
 269    rewrite_op_int_gt  = _rewrite_symmetric
 270    rewrite_op_int_ge  = _rewrite_symmetric
 271    rewrite_op_uint_lt = _rewrite_symmetric
 272    rewrite_op_uint_le = _rewrite_symmetric
 273    rewrite_op_uint_gt = _rewrite_symmetric
 274    rewrite_op_uint_ge = _rewrite_symmetric
 275
 276    rewrite_op_float_add = _rewrite_symmetric
 277    rewrite_op_float_mul = _rewrite_symmetric
 278    rewrite_op_float_lt  = _rewrite_symmetric
 279    rewrite_op_float_le  = _rewrite_symmetric
 280    rewrite_op_float_gt  = _rewrite_symmetric
 281    rewrite_op_float_ge  = _rewrite_symmetric
 282
 283    def rewrite_op_int_add_ovf(self, op):
 284        op0 = self._rewrite_symmetric(op)
 285        op1 = SpaceOperation('-live-', [], None)
 286        return [op0, op1]
 287
 288    rewrite_op_int_mul_ovf = rewrite_op_int_add_ovf
 289
 290    def rewrite_op_int_sub_ovf(self, op):
 291        op1 = SpaceOperation('-live-', [], None)
 292        return [op, op1]
 293
 294    def _noop_rewrite(self, op):
 295        return op
 296
 297    rewrite_op_convert_float_bytes_to_longlong = _noop_rewrite
 298    rewrite_op_convert_longlong_bytes_to_float = _noop_rewrite
 299
 300    # ----------
 301    # Various kinds of calls
 302
 303    def rewrite_op_direct_call(self, op):
 304        kind = self.callcontrol.guess_call_kind(op)
 305        return getattr(self, 'handle_%s_call' % kind)(op)
 306
 307    def rewrite_op_indirect_call(self, op):
 308        kind = self.callcontrol.guess_call_kind(op)
 309        return getattr(self, 'handle_%s_indirect_call' % kind)(op)
 310
 311    def rewrite_call(self, op, namebase, initialargs, args=None):
 312        """Turn 'i0 = direct_call(fn, i1, i2, ref1, ref2)'
 313           into 'i0 = xxx_call_ir_i(fn, descr, [i1,i2], [ref1,ref2])'.
 314           The name is one of '{residual,direct}_call_{r,ir,irf}_{i,r,f,v}'."""
 315        if args is None:
 316            args = op.args[1:]
 317        self._check_no_vable_array(args)
 318        lst_i, lst_r, lst_f = self.make_three_lists(args)
 319        reskind = getkind(op.result.concretetype)[0]
 320        if lst_f or reskind == 'f': kinds = 'irf'
 321        elif lst_i: kinds = 'ir'
 322        else: kinds = 'r'
 323        sublists = []
 324        if 'i' in kinds: sublists.append(lst_i)
 325        if 'r' in kinds: sublists.append(lst_r)
 326        if 'f' in kinds: sublists.append(lst_f)
 327        return SpaceOperation('%s_%s_%s' % (namebase, kinds, reskind),
 328                              initialargs + sublists, op.result)
 329
 330    def make_three_lists(self, vars):
 331        args_i = []
 332        args_r = []
 333        args_f = []
 334        for v in vars:
 335            self.add_in_correct_list(v, args_i, args_r, args_f)
 336        return [ListOfKind('int', args_i),
 337                ListOfKind('ref', args_r),
 338                ListOfKind('float', args_f)]
 339
 340    def add_in_correct_list(self, v, lst_i, lst_r, lst_f):
 341        kind = getkind(v.concretetype)
 342        if kind == 'void': return
 343        elif kind == 'int': lst = lst_i
 344        elif kind == 'ref': lst = lst_r
 345        elif kind == 'float': lst = lst_f
 346        else: raise AssertionError(kind)
 347        lst.append(v)
 348
 349    def handle_residual_call(self, op, extraargs=[], may_call_jitcodes=False):
 350        """A direct_call turns into the operation 'residual_call_xxx' if it
 351        is calling a function that we don't want to JIT.  The initial args
 352        of 'residual_call_xxx' are the function to call, and its calldescr."""
 353        calldescr = self.callcontrol.getcalldescr(op)
 354        op1 = self.rewrite_call(op, 'residual_call',
 355                                [op.args[0], calldescr] + extraargs)
 356        if may_call_jitcodes or self.callcontrol.calldescr_canraise(calldescr):
 357            op1 = [op1, SpaceOperation('-live-', [], None)]
 358        return op1
 359
 360    def handle_regular_call(self, op):
 361        """A direct_call turns into the operation 'inline_call_xxx' if it
 362        is calling a function that we want to JIT.  The initial arg of
 363        'inline_call_xxx' is the JitCode of the called function."""
 364        [targetgraph] = self.callcontrol.graphs_from(op)
 365        jitcode = self.callcontrol.get_jitcode(targetgraph,
 366                                               called_from=self.graph)
 367        op0 = self.rewrite_call(op, 'inline_call', [jitcode])
 368        op1 = SpaceOperation('-live-', [], None)
 369        return [op0, op1]
 370
 371    def handle_builtin_call(self, op):
 372        oopspec_name, args = support.decode_builtin_call(op)
 373        # dispatch to various implementations depending on the oopspec_name
 374        if oopspec_name.startswith('list.') or oopspec_name.startswith('newlist'):
 375            prepare = self._handle_list_call
 376        elif oopspec_name.startswith('stroruni.'):
 377            prepare = self._handle_stroruni_call
 378        elif oopspec_name == 'str.str2unicode':
 379            prepare = self._handle_str2unicode_call
 380        elif oopspec_name.startswith('virtual_ref'):
 381            prepare = self._handle_virtual_ref_call
 382        elif oopspec_name.startswith('jit.'):
 383            prepare = self._handle_jit_call
 384        elif oopspec_name.startswith('libffi_'):
 385            prepare = self._handle_libffi_call
 386        elif oopspec_name.startswith('math.sqrt'):
 387            prepare = self._handle_math_sqrt_call
 388        else:
 389            prepare = self.prepare_builtin_call
 390        try:
 391            op1 = prepare(op, oopspec_name, args)
 392        except NotSupported:
 393            op1 = op
 394        # If the resulting op1 is still a direct_call, turn it into a
 395        # residual_call.
 396        if isinstance(op1, SpaceOperation) and op1.opname == 'direct_call':
 397            op1 = self.handle_residual_call(op1)
 398        return op1
 399
 400    def handle_recursive_call(self, op):
 401        jitdriver_sd = self.callcontrol.jitdriver_sd_from_portal_runner_ptr(
 402            op.args[0].value)
 403        assert jitdriver_sd is not None
 404        ops = self.promote_greens(op.args[1:], jitdriver_sd.jitdriver)
 405        num_green_args = len(jitdriver_sd.jitdriver.greens)
 406        args = ([Constant(jitdriver_sd.index, lltype.Signed)] +
 407                self.make_three_lists(op.args[1:1+num_green_args]) +
 408                self.make_three_lists(op.args[1+num_green_args:]))
 409        kind = getkind(op.result.concretetype)[0]
 410        op0 = SpaceOperation('recursive_call_%s' % kind, args, op.result)
 411        op1 = SpaceOperation('-live-', [], None)
 412        return ops + [op0, op1]
 413
 414    handle_residual_indirect_call = handle_residual_call
 415
 416    def handle_regular_indirect_call(self, op):
 417        """An indirect call where at least one target has a JitCode."""
 418        lst = []
 419        for targetgraph in self.callcontrol.graphs_from(op):
 420            jitcode = self.callcontrol.get_jitcode(targetgraph,
 421                                                   called_from=self.graph)
 422            lst.append(jitcode)
 423        op0 = SpaceOperation('-live-', [], None)
 424        op1 = SpaceOperation('int_guard_value', [op.args[0]], None)
 425        op2 = self.handle_residual_call(op, [IndirectCallTargets(lst)], True)
 426        result = [op0, op1]
 427        if isinstance(op2, list):
 428            result += op2
 429        else:
 430            result.append(op2)
 431        return result
 432
 433    def prepare_builtin_call(self, op, oopspec_name, args,
 434                              extra=None, extrakey=None):
 435        argtypes = [v.concretetype for v in args]
 436        resulttype = op.result.concretetype
 437        c_func, TP = support.builtin_func_for_spec(self.cpu.rtyper,
 438                                                   oopspec_name, argtypes,
 439                                                   resulttype, extra, extrakey)
 440        return SpaceOperation('direct_call', [c_func] + args, op.result)
 441
 442    def _do_builtin_call(self, op, oopspec_name=None, args=None,
 443                         extra=None, extrakey=None):
 444        if oopspec_name is None: oopspec_name = op.opname
 445        if args is None: args = op.args
 446        op1 = self.prepare_builtin_call(op, oopspec_name, args,
 447                                        extra, extrakey)
 448        return self.rewrite_op_direct_call(op1)
 449
 450    # XXX some of the following functions should not become residual calls
 451    # but be really compiled
 452    rewrite_op_int_floordiv_ovf_zer = _do_builtin_call
 453    rewrite_op_int_floordiv_ovf     = _do_builtin_call
 454    rewrite_op_int_floordiv_zer     = _do_builtin_call
 455    rewrite_op_int_mod_ovf_zer = _do_builtin_call
 456    rewrite_op_int_mod_ovf     = _do_builtin_call
 457    rewrite_op_int_mod_zer     = _do_builtin_call
 458    rewrite_op_int_lshift_ovf  = _do_builtin_call
 459    rewrite_op_int_abs         = _do_builtin_call
 460    rewrite_op_llong_abs          = _do_builtin_call
 461    rewrite_op_llong_floordiv     = _do_builtin_call
 462    rewrite_op_llong_floordiv_zer = _do_builtin_call
 463    rewrite_op_llong_mod          = _do_builtin_call
 464    rewrite_op_llong_mod_zer      = _do_builtin_call
 465    rewrite_op_ullong_floordiv     = _do_builtin_call
 466    rewrite_op_ullong_floordiv_zer = _do_builtin_call
 467    rewrite_op_ullong_mod          = _do_builtin_call
 468    rewrite_op_ullong_mod_zer      = _do_builtin_call
 469    rewrite_op_gc_identityhash = _do_builtin_call
 470    rewrite_op_gc_id           = _do_builtin_call
 471    rewrite_op_uint_mod        = _do_builtin_call
 472    rewrite_op_cast_float_to_uint = _do_builtin_call
 473    rewrite_op_cast_uint_to_float = _do_builtin_call
 474
 475    # ----------
 476    # getfield/setfield/mallocs etc.
 477
 478    def rewrite_op_hint(self, op):
 479        hints = op.args[1].value
 480        if hints.get('promote') and op.args[0].concretetype is not lltype.Void:
 481            assert op.args[0].concretetype != lltype.Ptr(rstr.STR)
 482            kind = getkind(op.args[0].concretetype)
 483            op0 = SpaceOperation('-live-', [], None)
 484            op1 = SpaceOperation('%s_guard_value' % kind, [op.args[0]], None)
 485            # the special return value None forces op.result to be considered
 486            # equal to op.args[0]
 487            return [op0, op1, None]
 488        if (hints.get('promote_string') and
 489            op.args[0].concretetype is not lltype.Void):
 490            S = lltype.Ptr(rstr.STR)
 491            assert op.args[0].concretetype == S
 492            self._register_extra_helper(EffectInfo.OS_STREQ_NONNULL,
 493                                        "str.eq_nonnull",
 494                                        [S, S],
 495                                        lltype.Signed,
 496                                        EffectInfo.EF_ELIDABLE_CANNOT_RAISE)
 497            descr, p = self.callcontrol.callinfocollection.callinfo_for_oopspec(
 498                EffectInfo.OS_STREQ_NONNULL)
 499            # XXX this is fairly ugly way of creating a constant,
 500            #     however, callinfocollection has no better interface
 501            c = Constant(p.adr.ptr, lltype.typeOf(p.adr.ptr))
 502            op1 = SpaceOperation('str_guard_value', [op.args[0], c, descr],
 503                                 op.result)
 504            return [SpaceOperation('-live-', [], None), op1, None]
 505        else:
 506            log.WARNING('ignoring hint %r at %r' % (hints, self.graph))
 507
 508    def _rewrite_raw_malloc(self, op, name, args):
 509        d = op.args[1].value.copy()
 510        d.pop('flavor')
 511        add_memory_pressure = d.pop('add_memory_pressure', False)
 512        zero = d.pop('zero', False)
 513        track_allocation = d.pop('track_allocation', True)
 514        if d:
 515            raise UnsupportedMallocFlags(d)
 516        TYPE = op.args[0].value
 517        if zero:
 518            name += '_zero'
 519        if add_memory_pressure:
 520            name += '_add_memory_pressure'
 521        if not track_allocation:
 522            name += '_no_track_allocation'
 523        return self._do_builtin_call(op, name, args,
 524                                     extra = (TYPE,),
 525                                     extrakey = TYPE)
 526
 527    def rewrite_op_malloc_varsize(self, op):
 528        if op.args[1].value['flavor'] == 'raw':
 529            return self._rewrite_raw_malloc(op, 'raw_malloc_varsize',
 530                                            [op.args[2]])
 531        if op.args[0].value == rstr.STR:
 532            return SpaceOperation('newstr', [op.args[2]], op.result)
 533        elif op.args[0].value == rstr.UNICODE:
 534            return SpaceOperation('newunicode', [op.args[2]], op.result)
 535        else:
 536            # XXX only strings or simple arrays for now
 537            ARRAY = op.args[0].value
 538            arraydescr = self.cpu.arraydescrof(ARRAY)
 539            return SpaceOperation('new_array', [arraydescr, op.args[2]],
 540                                  op.result)
 541
 542    def rewrite_op_free(self, op):
 543        d = op.args[1].value.copy()
 544        assert d['flavor'] == 'raw'
 545        d.pop('flavor')
 546        track_allocation = d.pop('track_allocation', True)
 547        if d:
 548            raise UnsupportedMallocFlags(d)
 549        STRUCT = op.args[0].concretetype.TO
 550        name = 'raw_free'
 551        if not track_allocation:
 552            name += '_no_track_allocation'
 553        return self._do_builtin_call(op, name, [op.args[0]],
 554                                     extra = (STRUCT,), extrakey = STRUCT)
 555
 556    def rewrite_op_getarrayitem(self, op):
 557        ARRAY = op.args[0].concretetype.TO
 558        if self._array_of_voids(ARRAY):
 559            return []
 560        if op.args[0] in self.vable_array_vars:     # for virtualizables
 561            vars = self.vable_array_vars[op.args[0]]
 562            (v_base, arrayfielddescr, arraydescr) = vars
 563            kind = getkind(op.result.concretetype)
 564            return [SpaceOperation('-live-', [], None),
 565                    SpaceOperation('getarrayitem_vable_%s' % kind[0],
 566                                   [v_base, arrayfielddescr, arraydescr,
 567                                    op.args[1]], op.result)]
 568        # normal case follows
 569        arraydescr = self.cpu.arraydescrof(ARRAY)
 570        kind = getkind(op.result.concretetype)
 571        return SpaceOperation('getarrayitem_%s_%s' % (ARRAY._gckind, kind[0]),
 572                              [op.args[0], arraydescr, op.args[1]],
 573                              op.result)
 574
 575    def rewrite_op_setarrayitem(self, op):
 576        ARRAY = op.args[0].concretetype.TO
 577        if self._array_of_voids(ARRAY):
 578            return []
 579        if op.args[0] in self.vable_array_vars:     # for virtualizables
 580            vars = self.vable_array_vars[op.args[0]]
 581            (v_base, arrayfielddescr, arraydescr) = vars
 582            kind = getkind(op.args[2].concretetype)
 583            return [SpaceOperation('-live-', [], None),
 584                    SpaceOperation('setarrayitem_vable_%s' % kind[0],
 585                                   [v_base, arrayfielddescr, arraydescr,
 586                                    op.args[1], op.args[2]], None)]
 587        arraydescr = self.cpu.arraydescrof(ARRAY)
 588        kind = getkind(op.args[2].concretetype)
 589        return SpaceOperation('setarrayitem_%s_%s' % (ARRAY._gckind, kind[0]),
 590                              [op.args[0], arraydescr, op.args[1], op.args[2]],
 591                              None)
 592
 593    def rewrite_op_getarraysize(self, op):
 594        ARRAY = op.args[0].concretetype.TO
 595        assert ARRAY._gckind == 'gc'
 596        if op.args[0] in self.vable_array_vars:     # for virtualizables
 597            vars = self.vable_array_vars[op.args[0]]
 598            (v_base, arrayfielddescr, arraydescr) = vars
 599            return [SpaceOperation('-live-', [], None),
 600                    SpaceOperation('arraylen_vable',
 601                                   [v_base, arrayfielddescr, arraydescr],
 602                                   op.result)]
 603        # normal case follows
 604        arraydescr = self.cpu.arraydescrof(ARRAY)
 605        return SpaceOperation('arraylen_gc', [op.args[0], arraydescr],
 606                              op.result)
 607
 608    def _array_of_voids(self, ARRAY):
 609        #if isinstance(ARRAY, ootype.Array):
 610        #    return ARRAY.ITEM == ootype.Void
 611        #else:
 612        return ARRAY.OF == lltype.Void
 613
 614    def rewrite_op_getfield(self, op):
 615        if self.is_typeptr_getset(op):
 616            return self.handle_getfield_typeptr(op)
 617        # turn the flow graph 'getfield' operation into our own version
 618        [v_inst, c_fieldname] = op.args
 619        RESULT = op.result.concretetype
 620        if RESULT is lltype.Void:
 621            return
 622        # check for virtualizable
 623        try:
 624            if self.is_virtualizable_getset(op):
 625                descr = self.get_virtualizable_field_descr(op)
 626                kind = getkind(RESULT)[0]
 627                return [SpaceOperation('-live-', [], None),
 628                        SpaceOperation('getfield_vable_%s' % kind,
 629                                       [v_inst, descr], op.result)]
 630        except VirtualizableArrayField, e:
 631            # xxx hack hack hack
 632            vinfo = e.args[1]
 633            arrayindex = vinfo.array_field_counter[op.args[1].value]
 634            arrayfielddescr = vinfo.array_field_descrs[arrayindex]
 635            arraydescr = vinfo.array_descrs[arrayindex]
 636            self.vable_array_vars[op.result] = (op.args[0],
 637                                                arrayfielddescr,
 638                                                arraydescr)
 639            return []
 640        # check for _immutable_fields_ hints
 641        immut = v_inst.concretetype.TO._immutable_field(c_fieldname.value)
 642        if immut:
 643            if (self.callcontrol is not None and
 644                self.callcontrol.could_be_green_field(v_inst.concretetype.TO,
 645                                                      c_fieldname.value)):
 646                pure = '_greenfield'
 647            else:
 648                pure = '_pure'
 649        else:
 650            pure = ''
 651        self.check_field_access(v_inst.concretetype.TO)
 652        argname = getattr(v_inst.concretetype.TO, '_gckind', 'gc')
 653        descr = self.cpu.fielddescrof(v_inst.concretetype.TO,
 654                                      c_fieldname.value)
 655        kind = getkind(RESULT)[0]
 656        op1 = SpaceOperation('getfield_%s_%s%s' % (argname, kind, pure),
 657                             [v_inst, descr], op.result)
 658        #
 659        if immut in (IR_QUASIIMMUTABLE, IR_QUASIIMMUTABLE_ARRAY):
 660            descr1 = self.cpu.fielddescrof(
 661                v_inst.concretetype.TO,
 662                quasiimmut.get_mutate_field_name(c_fieldname.value))
 663            op1 = [SpaceOperation('-live-', [], None),
 664                   SpaceOperation('record_quasiimmut_field',
 665                                  [v_inst, descr, descr1], None),
 666                   op1]
 667        return op1
 668
 669    def rewrite_op_setfield(self, op):
 670        if self.is_typeptr_getset(op):
 671            # ignore the operation completely -- instead, it's done by 'new'
 672            return
 673        # turn the flow graph 'setfield' operation into our own version
 674        [v_inst, c_fieldname, v_value] = op.args
 675        RESULT = v_value.concretetype
 676        if RESULT is lltype.Void:
 677            return
 678        # check for virtualizable
 679        if self.is_virtualizable_getset(op):
 680            descr = self.get_virtualizable_field_descr(op)
 681            kind = getkind(RESULT)[0]
 682            return [SpaceOperation('-live-', [], None),
 683                    SpaceOperation('setfield_vable_%s' % kind,
 684                                   [v_inst, descr, v_value], None)]
 685        self.check_field_access(v_inst.concretetype.TO)
 686        argname = getattr(v_inst.concretetype.TO, '_gckind', 'gc')
 687        descr = self.cpu.fielddescrof(v_inst.concretetype.TO,
 688                                      c_fieldname.value)
 689        kind = getkind(RESULT)[0]
 690        return SpaceOperation('setfield_%s_%s' % (argname, kind),
 691                              [v_inst, descr, v_value],
 692                              None)
 693
 694    def is_typeptr_getset(self, op):
 695        return (op.args[1].value == 'typeptr' and
 696                op.args[0].concretetype.TO._hints.get('typeptr'))
 697
 698    def check_field_access(self, STRUCT):
 699        # check against a GcStruct with a nested GcStruct as a first argument
 700        # but which is not an object at all; see metainterp/test/test_loop,
 701        # test_regular_pointers_in_short_preamble.
 702        if not isinstance(STRUCT, lltype.GcStruct):
 703            return
 704        if STRUCT._first_struct() == (None, None):
 705            return
 706        PARENT = STRUCT
 707        while not PARENT._hints.get('typeptr'):
 708            _, PARENT = PARENT._first_struct()
 709            if PARENT is None:
 710                raise NotImplementedError("%r is a GcStruct using nesting but "
 711                                          "not inheriting from object" %
 712                                          (STRUCT,))
 713
 714    def get_vinfo(self, v_virtualizable):
 715        if self.callcontrol is None:      # for tests
 716            return None
 717        return self.callcontrol.get_vinfo(v_virtualizable.concretetype)
 718
 719    def is_virtualizable_getset(self, op):
 720        # every access of an object of exactly the type VTYPEPTR is
 721        # likely to be a virtualizable access, but we still have to
 722        # check it in pyjitpl.py.
 723        vinfo = self.get_vinfo(op.args[0])
 724        if vinfo is None:
 725            return False
 726        res = False
 727        if op.args[1].value in vinfo.static_field_to_extra_box:
 728            res = True
 729        if op.args[1].value in vinfo.array_fields:
 730            res = VirtualizableArrayField(self.graph, vinfo)
 731
 732        if res:
 733            flags = self.vable_flags[op.args[0]]
 734            if 'fresh_virtualizable' in flags:
 735                return False
 736        if isinstance(res, Exception):
 737            raise res
 738        return res
 739
 740    def get_virtualizable_field_descr(self, op):
 741        fieldname = op.args[1].value
 742        vinfo = self.get_vinfo(op.args[0])
 743        index = vinfo.static_field_to_extra_box[fieldname]
 744        return vinfo.static_field_descrs[index]
 745
 746    def handle_getfield_typeptr(self, op):
 747        if isinstance(op.args[0], Constant):
 748            cls = op.args[0].value.typeptr
 749            return Constant(cls, concretetype=rclass.CLASSTYPE)
 750        op0 = SpaceOperation('-live-', [], None)
 751        op1 = SpaceOperation('guard_class', [op.args[0]], op.result)
 752        return [op0, op1]
 753
 754    def rewrite_op_malloc(self, op):
 755        if op.args[1].value['flavor'] == 'raw':
 756            return self._rewrite_raw_malloc(op, 'raw_malloc_fixedsize', [])
 757        #
 758        assert op.args[1].value == {'flavor': 'gc'}
 759        STRUCT = op.args[0].value
 760        vtable = heaptracker.get_vtable_for_gcstruct(self.cpu, STRUCT)
 761        if vtable:
 762            # do we have a __del__?
 763            try:
 764                rtti = lltype.getRuntimeTypeInfo(STRUCT)
 765            except ValueError:
 766                pass
 767            else:
 768                if hasattr(rtti._obj, 'destructor_funcptr'):
 769                    RESULT = lltype.Ptr(STRUCT)
 770                    assert RESULT == op.result.concretetype
 771                    return self._do_builtin_call(op, 'alloc_with_del', [],
 772                                                 extra = (RESULT, vtable),
 773                                                 extrakey = STRUCT)
 774            heaptracker.register_known_gctype(self.cpu, vtable, STRUCT)
 775            opname = 'new_with_vtable'
 776        else:
 777            opname = 'new'
 778        sizedescr = self.cpu.sizeof(STRUCT)
 779        return SpaceOperation(opname, [sizedescr], op.result)
 780
 781    def rewrite_op_getinteriorarraysize(self, op):
 782        # only supports strings and unicodes
 783        assert len(op.args) == 2
 784        assert op.args[1].value == 'chars'
 785        optype = op.args[0].concretetype
 786        if optype == lltype.Ptr(rstr.STR):
 787            opname = "strlen"
 788        else:
 789            assert optype == lltype.Ptr(rstr.UNICODE)
 790            opname = "unicodelen"
 791        return SpaceOperation(opname, [op.args[0]], op.result)
 792
 793    def rewrite_op_getinteriorfield(self, op):
 794        assert len(op.args) == 3
 795        optype = op.args[0].concretetype
 796        if optype == lltype.Ptr(rstr.STR):
 797            opname = "strgetitem"
 798            return SpaceOperation(opname, [op.args[0], op.args[2]], op.result)
 799        elif optype == lltype.Ptr(rstr.UNICODE):
 800            opname = "unicodegetitem"
 801            return SpaceOperation(opname, [op.args[0], op.args[2]], op.result)
 802        else:
 803            v_inst, v_index, c_field = op.args
 804            if op.result.concretetype is lltype.Void:
 805                return
 806            # only GcArray of Struct supported
 807            assert isinstance(v_inst.concretetype.TO, lltype.GcArray)
 808            STRUCT = v_inst.concretetype.TO.OF
 809            assert isinstance(STRUCT, lltype.Struct)
 810            descr = self.cpu.interiorfielddescrof(v_inst.concretetype.TO,
 811                                                  c_field.value)
 812            args = [v_inst, v_index, descr]
 813            kind = getkind(op.result.concretetype)[0]
 814            return SpaceOperation('getinteriorfield_gc_%s' % kind, args,
 815                                  op.result)
 816
 817    def rewrite_op_setinteriorfield(self, op):
 818        assert len(op.args) == 4
 819        optype = op.args[0].concretetype
 820        if optype == lltype.Ptr(rstr.STR):
 821            opname = "strsetitem"
 822            return SpaceOperation(opname, [op.args[0], op.args[2], op.args[3]],
 823                                  op.result)
 824        elif optype == lltype.Ptr(rstr.UNICODE):
 825            opname = "unicodesetitem"
 826            return SpaceOperation(opname, [op.args[0], op.args[2], op.args[3]],
 827                                  op.result)
 828        else:
 829            v_inst, v_index, c_field, v_value = op.args
 830            if v_value.concretetype is lltype.Void:
 831                return
 832            # only GcArray of Struct supported
 833            assert isinstance(v_inst.concretetype.TO, lltype.GcArray)
 834            STRUCT = v_inst.concretetype.TO.OF
 835            assert isinstance(STRUCT, lltype.Struct)
 836            descr = self.cpu.interiorfielddescrof(v_inst.concretetype.TO,
 837                                                  c_field.value)
 838            kind = getkind(v_value.concretetype)[0]
 839            args = [v_inst, v_index, v_value, descr]
 840            return SpaceOperation('setinteriorfield_gc_%s' % kind, args,
 841                                  op.result)
 842
 843    def _rewrite_equality(self, op, opname):
 844        arg0, arg1 = op.args
 845        if isinstance(arg0, Constant) and not arg0.value:
 846            return SpaceOperation(opname, [arg1], op.result)
 847        elif isinstance(arg1, Constant) and not arg1.value:
 848            return SpaceOperation(opname, [arg0], op.result)
 849        else:
 850            return self._rewrite_symmetric(op)
 851
 852    def _is_gc(self, v):
 853        return getattr(getattr(v.concretetype, "TO", None), "_gckind", "?") == 'gc'
 854
 855    def _is_rclass_instance(self, v):
 856        return lltype._castdepth(v.concretetype.TO, rclass.OBJECT) >= 0
 857
 858    def _rewrite_cmp_ptrs(self, op):
 859        if self._is_gc(op.args[0]):
 860            return op
 861        else:
 862            opname = {'ptr_eq': 'int_eq',
 863                      'ptr_ne': 'int_ne',
 864                      'ptr_iszero': 'int_is_zero',
 865                      'ptr_nonzero': 'int_is_true'}[op.opname]
 866            return SpaceOperation(opname, op.args, op.result)
 867
 868    def rewrite_op_int_eq(self, op):
 869        return self._rewrite_equality(op, 'int_is_zero')
 870
 871    def rewrite_op_int_ne(self, op):
 872        return self._rewrite_equality(op, 'int_is_true')
 873
 874    def rewrite_op_ptr_eq(self, op):
 875        prefix = ''
 876        if self._is_rclass_instance(op.args[0]):
 877            assert self._is_rclass_instance(op.args[1])
 878            op = SpaceOperation('instance_ptr_eq', op.args, op.result)
 879            prefix = 'instance_'
 880        op1 = self._rewrite_equality(op, prefix + 'ptr_iszero')
 881        return self._rewrite_cmp_ptrs(op1)
 882
 883    def rewrite_op_ptr_ne(self, op):
 884        prefix = ''
 885        if self._is_rclass_instance(op.args[0]):
 886            assert self._is_rclass_instance(op.args[1])
 887            op = SpaceOperation('instance_ptr_ne', op.args, op.result)
 888            prefix = 'instance_'
 889        op1 = self._rewrite_equality(op, prefix + 'ptr_nonzero')
 890        return self._rewrite_cmp_ptrs(op1)
 891
 892    rewrite_op_ptr_iszero = _rewrite_cmp_ptrs
 893    rewrite_op_ptr_nonzero = _rewrite_cmp_ptrs
 894
 895    def rewrite_op_cast_ptr_to_int(self, op):
 896        if self._is_gc(op.args[0]):
 897            return op
 898
 899    def rewrite_op_cast_opaque_ptr(self, op):
 900        # None causes the result of this op to get aliased to op.args[0]
 901        return [SpaceOperation('mark_opaque_ptr', op.args, None), None]
 902
 903    def rewrite_op_force_cast(self, op):
 904        v_arg = op.args[0]
 905        v_result = op.result
 906        assert not self._is_gc(v_arg)
 907
 908        if v_arg.concretetype == v_result.concretetype:
 909            return
 910
 911        float_arg = v_arg.concretetype in [lltype.Float, lltype.SingleFloat]
 912        float_res = v_result.concretetype in [lltype.Float, lltype.SingleFloat]
 913        if not float_arg and not float_res:
 914            # some int -> some int cast
 915            return self._int_to_int_cast(v_arg, v_result)
 916        elif float_arg and float_res:
 917            # some float -> some float cast
 918            return self._float_to_float_cast(v_arg, v_result)
 919        elif not float_arg and float_res:
 920            # some int -> some float
 921            ops = []
 922            v2 = varoftype(lltype.Float)
 923            sizesign = rffi.size_and_sign(v_arg.concretetype)
 924            if sizesign <= rffi.size_and_sign(lltype.Signed):
 925                # cast from a type that fits in an int: either the size is
 926                # smaller, or it is equal and it is not unsigned
 927                v1 = varoftype(lltype.Signed)
 928                oplist = self.rewrite_operation(
 929                    SpaceOperation('force_cast', [v_arg], v1)
 930                )
 931                if oplist:
 932                    ops.extend(oplist)
 933                else:
 934                    v1 = v_arg
 935                op = self.rewrite_operation(
 936                    SpaceOperation('cast_int_to_float', [v1], v2)
 937                )
 938                ops.append(op)
 939            else:
 940                if sizesign == rffi.size_and_sign(lltype.Unsigned):
 941                    opname = 'cast_uint_to_float'
 942                elif sizesign == rffi.size_and_sign(lltype.SignedLongLong):
 943                    opname = 'cast_longlong_to_float'
 944                elif sizesign == rffi.size_and_sign(lltype.UnsignedLongLong):
 945                    opname = 'cast_ulonglong_to_float'
 946                else:
 947                    raise AssertionError('cast_x_to_float: %r' % (sizesign,))
 948                ops1 = self.rewrite_operation(
 949                    SpaceOperation(opname, [v_arg], v2)
 950                )
 951                if not isinstance(ops1, list): ops1 = [ops1]
 952                ops.extend(ops1)
 953            op2 = self.rewrite_operation(
 954                SpaceOperation('force_cast', [v2], v_result)
 955            )
 956            if op2:
 957                ops.append(op2)
 958            else:
 959                ops[-1].result = v_result
 960            return ops
 961        elif float_arg and not float_res:
 962            # some float -> some int
 963            ops = []
 964            v1 = varoftype(lltype.Float)
 965            op1 = self.rewrite_operation(
 966                SpaceOperation('force_cast', [v_arg], v1)
 967            )
 968            if op1:
 969                ops.append(op1)
 970            else:
 971                v1 = v_arg
 972            sizesign = rffi.size_and_sign(v_result.concretetype)
 973            if sizesign <= rffi.size_and_sign(lltype.Signed):
 974                # cast to a type that fits in an int: either the size is
 975                # smaller, or it is equal and it is not unsigned
 976                v2 = varoftype(lltype.Signed)
 977                op = self.rewrite_operation(
 978                    SpaceOperation('cast_float_to_int', [v1], v2)
 979                )
 980                ops.append(op)
 981                oplist = self.rewrite_operation(
 982                    SpaceOperation('force_cast', [v2], v_result)
 983                )
 984                if oplist:
 985                    ops.extend(oplist)
 986                else:
 987                    op.result = v_result
 988            else:
 989                if sizesign == rffi.size_and_sign(lltype.Unsigned):
 990                    opname = 'cast_float_to_uint'
 991                elif sizesign == rffi.size_and_sign(lltype.SignedLongLong):
 992                    opname = 'cast_float_to_longlong'
 993                elif sizesign == rffi.size_and_sign(lltype.UnsignedLongLong):
 994                    opname = 'cast_float_to_ulonglong'
 995                else:
 996                    raise AssertionError('cast_float_to_x: %r' % (sizesign,))
 997                ops1 = self.rewrite_operation(
 998                    SpaceOperation(opname, [v1], v_result)
 999                )
1000                if not isinstance(ops1, list): ops1 = [ops1]
1001                ops.extend(ops1)
1002            return ops
1003        else:
1004            assert False
1005
1006    def _int_to_int_cast(self, v_arg, v_result):
1007        longlong_arg = longlong.is_longlong(v_arg.concretetype)
1008        longlong_res = longlong.is_longlong(v_result.concretetype)
1009        size1, unsigned1 = rffi.size_and_sign(v_arg.concretetype)
1010        size2, unsigned2 = rffi.size_and_sign(v_result.concretetype)
1011
1012        if longlong_arg and longlong_res:
1013            return
1014        elif longlong_arg:
1015            v = varoftype(lltype.Signed)
1016            op1 = self.rewrite_operation(
1017                SpaceOperation('truncate_longlong_to_int', [v_arg], v)
1018            )
1019            op2 = SpaceOperation('force_cast', [v], v_result)
1020            oplist = self.rewrite_operation(op2)
1021            if not oplist:
1022                op1.result = v_result
1023                oplist = []
1024            return [op1] + oplist
1025        elif longlong_res:
1026            if unsigned1:
1027                INTERMEDIATE = lltype.Unsigned
1028            else:
1029                INTERMEDIATE = lltype.Signed
1030            v = varoftype(INTERMEDIATE)
1031            op1 = SpaceOperation('force_cast', [v_arg], v)
1032            oplist = self.rewrite_operation(op1)
1033            if not oplist:
1034                v = v_arg
1035                oplist = []
1036            if unsigned1:
1037                if unsigned2:
1038                    opname = 'cast_uint_to_ulonglong'
1039                else:
1040                    opname = 'cast_uint_to_longlong'
1041            else:
1042                if unsigned2:
1043                    opname = 'cast_int_to_ulonglong'
1044                else:
1045                    opname = 'cast_int_to_longlong'
1046            op2 = self.rewrite_operation(
1047                SpaceOperation(opname, [v], v_result)
1048            )
1049            return oplist + [op2]
1050
1051        # We've now, ostensibly, dealt with the longlongs, everything should be
1052        # a Signed or smaller
1053        assert size1 <= rffi.sizeof(lltype.Signed)
1054        assert size2 <= rffi.sizeof(lltype.Signed)
1055
1056        # the target type is LONG or ULONG
1057        if size2 == rffi.sizeof(lltype.Signed):
1058            return
1059
1060        min1, max1 = integer_bounds(size1, unsigned1)
1061        min2, max2 = integer_bounds(size2, unsigned2)
1062
1063        # the target type includes the source range
1064        if min2 <= min1 <= max1 <= max2:
1065            return
1066
1067        result = []
1068        if min2:
1069            c_min2 = Constant(min2, lltype.Signed)
1070            v2 = varoftype(lltype.Signed)
1071            result.append(SpaceOperation('int_sub', [v_arg, c_min2], v2))
1072        else:
1073            v2 = v_arg
1074        c_mask = Constant(int((1 << (8 * size2)) - 1), lltype.Signed)
1075        if min2:
1076            v3 = varoftype(lltype.Signed)
1077        else:
1078            v3 = v_result
1079        result.append(SpaceOperation('int_and', [v2, c_mask], v3))
1080        if min2:
1081            result.append(SpaceOperation('int_add', [v3, c_min2], v_result))
1082        return result
1083
1084    def _float_to_float_cast(self, v_arg, v_result):
1085        if v_arg.concretetype == lltype.SingleFloat:
1086            assert v_result.concretetype == lltype.Float, "cast %s -> %s" % (
1087                v_arg.concretetype, v_result.concretetype)
1088            return SpaceOperation('cast_singlefloat_to_float', [v_arg],
1089                                  v_result)
1090        if v_result.concretetype == lltype.SingleFloat:
1091            assert v_arg.concretetype == lltype.Float, "cast %s -> %s" % (
1092                v_arg.concretetype, v_result.concretetype)
1093            return SpaceOperation('cast_float_to_singlefloat', [v_arg],
1094                                  v_result)
1095
1096    def rewrite_op_direct_ptradd(self, op):
1097        # xxx otherwise, not implemented:
1098        assert op.args[0].concretetype == rffi.CCHARP
1099        #
1100        return SpaceOperation('int_add', [op.args[0], op.args[1]], op.result)
1101
1102    # ----------
1103    # Long longs, for 32-bit only.  Supported operations are left unmodified,
1104    # and unsupported ones are turned into a call to a function from
1105    # jit.codewriter.support.
1106
1107    for _op, _oopspec in [('llong_invert',  'INVERT'),
1108                          ('llong_lt',      'LT'),
1109                          ('llong_le',      'LE'),
1110                          ('llong_eq',      'EQ'),
1111                          ('llong_ne',      'NE'),
1112                          ('llong_gt',      'GT'),
1113                          ('llong_ge',      'GE'),
1114                          ('llong_add',     'ADD'),
1115                          ('llong_sub',     'SUB'),
1116                          ('llong_mul',     'MUL'),
1117                          ('llong_and',     'AND'),
1118                          ('llong_or',      'OR'),
1119                          ('llong_xor',     'XOR'),
1120                          ('llong_lshift',  'LSHIFT'),
1121                          ('llong_rshift',  'RSHIFT'),
1122                          ('cast_int_to_longlong',     'FROM_INT'),
1123                          ('truncate_longlong_to_int', 'TO_INT'),
1124                          ('cast_float_to_longlong',   'FROM_FLOAT'),
1125                          ('cast_longlong_to_float',   'TO_FLOAT'),
1126                          ('cast_uint_to_longlong',    'FROM_UINT'),
1127                          ]:
1128        exec py.code.Source('''
1129            def rewrite_op_%s(self, op):
1130                args = op.args
1131                op1 = self.prepare_builtin_call(op, "llong_%s", args)
1132                op2 = self._handle_oopspec_call(op1, args,
1133                                                EffectInfo.OS_LLONG_%s,
1134                                           EffectInfo.EF_ELIDABLE_CANNOT_RAISE)
1135                if %r == "TO_INT":
1136                    assert op2.result.concretetype == lltype.Signed
1137                return op2
1138        ''' % (_op, _oopspec.lower(), _oopspec, _oopspec)).compile()
1139
1140    for _op, _oopspec in [('cast_int_to_ulonglong',     'FROM_INT'),
1141                          ('cast_uint_to_ulonglong',    'FROM_UINT'),
1142                          ('cast_float_to_ulonglong',   'FROM_FLOAT'),
1143                          ('cast_ulonglong_to_float',   'U_TO_FLOAT'),
1144     

Large files files are truncated, but you can click here to view the full file