Ejemplo n.º 1
0
 def emit_gc_load_or_indexed(self, op, ptr_box, index_box, itemsize,
                             factor, offset, sign, type='i'):
     factor, offset, index_box = \
             self._emit_mul_if_factor_offset_not_supported(index_box,
                     factor, offset)
     #
     if sign:
         # encode signed into the itemsize value
         itemsize = -itemsize
     #
     optype = type
     if op is not None:
         optype = op.type
     if index_box is None:
         args = [ptr_box, ConstInt(offset), ConstInt(itemsize)]
         newload = ResOperation(OpHelpers.get_gc_load(optype), args)
     else:
         args = [ptr_box, index_box, ConstInt(factor),
                 ConstInt(offset), ConstInt(itemsize)]
         newload = ResOperation(OpHelpers.get_gc_load_indexed(optype), args)
     if op is None:
         self.emit_op(newload)
     else:
         self.replace_op_with(op, newload)
     return newload
Ejemplo n.º 2
0
def expand(state, pack, args, arg, index):
    """ Expand a value into a vector box. useful for arith metic
        of one vector with a scalar (either constant/varialbe)
    """
    left = pack.leftmost()
    box_type = arg.type
    expanded_map = state.expanded_map

    ops = state.invariant_oplist
    variables = state.invariant_vector_vars
    if not arg.is_constant() and arg not in state.inputargs:
        # cannot be created before the loop, expand inline
        ops = state.oplist
        variables = None

    for i, node in enumerate(pack.operations):
        op = node.getoperation()
        if not arg.same_box(op.getarg(index)):
            break
        i += 1
    else:
        # note that heterogenous nodes are not yet tracked
        vecop = state.find_expanded([arg])
        if vecop:
            args[index] = vecop
            return vecop
        left = pack.leftmost()
        vecinfo = forwarded_vecinfo(left)
        vecop = OpHelpers.create_vec_expand(arg, vecinfo.bytesize, vecinfo.signed, pack.numops())
        ops.append(vecop)
        if variables is not None:
            variables.append(vecop)
        state.expand([arg], vecop)
        args[index] = vecop
        return vecop

    # quick search if it has already been expanded
    expandargs = [op.getoperation().getarg(index) for op in pack.operations]
    vecop = state.find_expanded(expandargs)
    if vecop:
        args[index] = vecop
        return vecop

    arg_vecinfo = forwarded_vecinfo(arg)
    vecop = OpHelpers.create_vec(arg.type, arg_vecinfo.bytesize, arg_vecinfo.signed, pack.opnum())
    ops.append(vecop)
    for i,node in enumerate(pack.operations):
        op = node.getoperation()
        arg = op.getarg(index)
        arguments = [vecop, arg, ConstInt(i), ConstInt(1)]
        vecinfo = forwarded_vecinfo(vecop)
        vecop = OpHelpers.create_vec_pack(arg.type, arguments, vecinfo.bytesize,
                                          vecinfo.signed, vecinfo.count+1)
        ops.append(vecop)
    state.expand(expandargs, vecop)

    if variables is not None:
        variables.append(vecop)
    args[index] = vecop
Ejemplo n.º 3
0
def expand(state, pack, args, arg, index):
    """ Expand a value into a vector box. useful for arith metic
        of one vector with a scalar (either constant/varialbe)
    """
    left = pack.leftmost()
    box_type = arg.type
    expanded_map = state.expanded_map

    ops = state.invariant_oplist
    variables = state.invariant_vector_vars
    if not arg.is_constant() and arg not in state.inputargs:
        # cannot be created before the loop, expand inline
        ops = state.oplist
        variables = None

    for i, node in enumerate(pack.operations):
        op = node.getoperation()
        if not arg.same_box(op.getarg(index)):
            break
        i += 1
    else:
        # note that heterogenous nodes are not yet tracked
        vecop = state.find_expanded([arg])
        if vecop:
            args[index] = vecop
            return vecop
        left = pack.leftmost()
        vecinfo = forwarded_vecinfo(left)
        vecop = OpHelpers.create_vec_expand(arg, vecinfo.bytesize, vecinfo.signed, pack.numops())
        ops.append(vecop)
        if variables is not None:
            variables.append(vecop)
        state.expand([arg], vecop)
        args[index] = vecop
        return vecop

    # quick search if it has already been expanded
    expandargs = [op.getoperation().getarg(index) for op in pack.operations]
    vecop = state.find_expanded(expandargs)
    if vecop:
        args[index] = vecop
        return vecop

    arg_vecinfo = forwarded_vecinfo(arg)
    vecop = OpHelpers.create_vec(arg.type, arg_vecinfo.bytesize, arg_vecinfo.signed, pack.opnum())
    ops.append(vecop)
    for i,node in enumerate(pack.operations):
        op = node.getoperation()
        arg = op.getarg(index)
        arguments = [vecop, arg, ConstInt(i), ConstInt(1)]
        vecinfo = forwarded_vecinfo(vecop)
        vecop = OpHelpers.create_vec_pack(arg.type, arguments, vecinfo.bytesize,
                                          vecinfo.signed, vecinfo.count+1)
        ops.append(vecop)
    state.expand(expandargs, vecop)

    if variables is not None:
        variables.append(vecop)
    args[index] = vecop
Ejemplo n.º 4
0
    def clear_caches(self, opnum, descr, argboxes):
        if (opnum == rop.SETFIELD_GC or
            opnum == rop.SETARRAYITEM_GC or
            opnum == rop.SETFIELD_RAW or
            opnum == rop.SETARRAYITEM_RAW or
            opnum == rop.SETINTERIORFIELD_GC or
            opnum == rop.COPYSTRCONTENT or
            opnum == rop.COPYUNICODECONTENT or
            opnum == rop.STRSETITEM or
            opnum == rop.UNICODESETITEM or
            opnum == rop.SETFIELD_RAW or
            opnum == rop.SETARRAYITEM_RAW or
            opnum == rop.SETINTERIORFIELD_RAW or
            opnum == rop.RECORD_EXACT_CLASS or
            opnum == rop.RAW_STORE or
            opnum == rop.ASSERT_NOT_NONE):
            return
        if (rop._OVF_FIRST <= opnum <= rop._OVF_LAST or
            rop._NOSIDEEFFECT_FIRST <= opnum <= rop._NOSIDEEFFECT_LAST or
            rop._GUARD_FIRST <= opnum <= rop._GUARD_LAST):
            return
        self.need_guard_not_invalidated = True # can do better, but good start
        if (OpHelpers.is_plain_call(opnum) or
            OpHelpers.is_call_loopinvariant(opnum) or
            OpHelpers.is_cond_call_value(opnum) or
            opnum == rop.COND_CALL):
            effectinfo = descr.get_extra_info()
            ef = effectinfo.extraeffect
            if (ef == effectinfo.EF_LOOPINVARIANT or
                ef == effectinfo.EF_ELIDABLE_CANNOT_RAISE or
                ef == effectinfo.EF_ELIDABLE_OR_MEMORYERROR or
                ef == effectinfo.EF_ELIDABLE_CAN_RAISE):
                return
            # A special case for ll_arraycopy, because it is so common, and its
            # effects are so well defined.
            elif effectinfo.oopspecindex == effectinfo.OS_ARRAYCOPY:
                self._clear_caches_arraycopy(opnum, descr, argboxes, effectinfo)
                return
            elif effectinfo.oopspecindex == effectinfo.OS_ARRAYMOVE:
                self._clear_caches_arraymove(opnum, descr, argboxes, effectinfo)
                return
            else:
                # Only invalidate things that are escaped
                # XXX can do better, only do it for the descrs in the effectinfo
                for descr, cache in self.heap_cache.iteritems():
                    cache.invalidate_unescaped()
                for descr, indices in self.heap_array_cache.iteritems():
                    for cache in indices.itervalues():
                        cache.invalidate_unescaped()
                return

        # XXX not completely sure, but I *think* it is needed to reset() the
        # state at least in the 'CALL_*' operations that release the GIL.  We
        # tried to do only the kind of resetting done by the two loops just
        # above, but hit an assertion in "pypy test_multiprocessing.py".
        self.reset_keep_likely_virtuals()
Ejemplo n.º 5
0
    def clear_caches(self, opnum, descr, argboxes):
        if (opnum == rop.SETFIELD_GC or
            opnum == rop.SETARRAYITEM_GC or
            opnum == rop.SETFIELD_RAW or
            opnum == rop.SETARRAYITEM_RAW or
            opnum == rop.SETINTERIORFIELD_GC or
            opnum == rop.COPYSTRCONTENT or
            opnum == rop.COPYUNICODECONTENT or
            opnum == rop.STRSETITEM or
            opnum == rop.UNICODESETITEM or
            opnum == rop.SETFIELD_RAW or
            opnum == rop.SETARRAYITEM_RAW or
            opnum == rop.SETINTERIORFIELD_RAW or
            opnum == rop.RAW_STORE):
            return
        if (rop._OVF_FIRST <= opnum <= rop._OVF_LAST or
            rop._NOSIDEEFFECT_FIRST <= opnum <= rop._NOSIDEEFFECT_LAST or
            rop._GUARD_FIRST <= opnum <= rop._GUARD_LAST):
            return
        if (OpHelpers.is_plain_call(opnum) or
            OpHelpers.is_call_loopinvariant(opnum) or
            OpHelpers.is_cond_call_value(opnum) or
            opnum == rop.COND_CALL):
            effectinfo = descr.get_extra_info()
            ef = effectinfo.extraeffect
            if (ef == effectinfo.EF_LOOPINVARIANT or
                ef == effectinfo.EF_ELIDABLE_CANNOT_RAISE or
                ef == effectinfo.EF_ELIDABLE_OR_MEMORYERROR or
                ef == effectinfo.EF_ELIDABLE_CAN_RAISE):
                return
            # A special case for ll_arraycopy, because it is so common, and its
            # effects are so well defined.
            elif effectinfo.oopspecindex == effectinfo.OS_ARRAYCOPY:
                self._clear_caches_arraycopy(opnum, descr, argboxes, effectinfo)
                return
            else:
                # Only invalidate things that are escaped
                # XXX can do better, only do it for the descrs in the effectinfo
                for descr, cache in self.heap_cache.iteritems():
                    cache.invalidate_unescaped()
                for descr, indices in self.heap_array_cache.iteritems():
                    for cache in indices.itervalues():
                        cache.invalidate_unescaped()
                return

        # XXX not completely sure, but I *think* it is needed to reset() the
        # state at least in the 'CALL_*' operations that release the GIL.  We
        # tried to do only the kind of resetting done by the two loops just
        # above, but hit an assertion in "pypy test_multiprocessing.py".
        self.reset_keep_likely_virtuals()
Ejemplo n.º 6
0
 def accumulate_prepare(self, state):
     vec_reg_size = state.vec_reg_size
     for pack in self.packs:
         if not pack.is_accumulating():
             continue
         if pack.leftmost().is_guard():
             # guard breaks dependencies, thus it is an accumulation pack
             continue
         for i,node in enumerate(pack.operations):
             op = node.getoperation()
             state.accumulation[op] = pack
         assert isinstance(pack, AccumPack)
         datatype = pack.getdatatype()
         bytesize = pack.getbytesize()
         count = vec_reg_size // bytesize
         signed = datatype == 'i'
         oplist = state.invariant_oplist
         # reset the box to zeros or ones
         if pack.reduce_init() == 0:
             vecop = OpHelpers.create_vec(datatype, bytesize, signed, count)
             oplist.append(vecop)
             opnum = rop.VEC_INT_XOR
             if datatype == FLOAT:
                 # see PRECISION loss below
                 raise NotImplementedError
             vecop = VecOperation(opnum, [vecop, vecop],
                                  vecop, count)
             oplist.append(vecop)
         elif pack.reduce_init() == 1:
             # PRECISION loss, because the numbers are accumulated (associative, commutative properties must hold)
             # you can end up a small number and a huge number that is finally multiplied. giving an
             # inprecision result, thus this is disabled now
             raise NotImplementedError
             # multiply is only supported by floats
             vecop = OpHelpers.create_vec_expand(ConstFloat(1.0), bytesize,
                                                 signed, count)
             oplist.append(vecop)
         else:
             raise NotImplementedError("cannot handle %s" % pack.operator)
         # pack the scalar value
         args = [vecop, pack.getleftmostseed(), ConstInt(0), ConstInt(1)]
         vecop = OpHelpers.create_vec_pack(datatype, args, bytesize,
                                           signed, count)
         oplist.append(vecop)
         seed = pack.getleftmostseed()
         state.accumulation[seed] = pack
         # rename the variable with the box
         state.setvector_of_box(seed, 0, vecop) # prevent it from expansion
         state.renamer.start_renaming(seed, vecop)
Ejemplo n.º 7
0
    def produce_potential_short_preamble_ops(self, sb):
        ops = self.optimizer._newoperations
        for i, op in enumerate(ops):
            if rop.is_always_pure(op.opnum):
                sb.add_pure_op(op)
            if rop.is_ovf(
                    op.opnum) and ops[i +
                                      1].getopnum() == rop.GUARD_NO_OVERFLOW:
                sb.add_pure_op(op)
        for i in self.call_pure_positions:
            op = ops[i]
            # don't move call_pure_with_exception in the short preamble...
            # issue #2015

            # Also, don't move cond_call_value in the short preamble.
            # The issue there is that it's usually pointless to try to
            # because the 'value' argument is typically not a loop
            # invariant, and would really need to be in order to end up
            # in the short preamble.  Maybe the code works anyway in the
            # other rare case, but better safe than sorry and don't try.
            effectinfo = op.getdescr().get_extra_info()
            if not effectinfo.check_can_raise(ignore_memoryerror=True):
                assert rop.is_call(op.opnum)
                if not OpHelpers.is_cond_call_value(op.opnum):
                    sb.add_pure_op(op)
Ejemplo n.º 8
0
 def inputarg_for_var(self, elem):
     try:
         return self._cache[elem]
     except KeyError:
         pass
     if elem[0] in 'ifrpv':
         box = OpHelpers.inputarg_from_tp(elem[0])
         number = elem[1:]
         if elem.startswith('v'):
             pattern = re.compile('.*\[(\d+)x(i|f)(\d+)\]')
             match = pattern.match(elem)
             if match:
                 box.datatype = match.group(2)[0]
                 box.bytesize = int(match.group(3)) // 8
                 box.count = int(match.group(1))
                 box.signed == item_type == 'i'
                 number = elem[1:elem.find('[')]
     else:
         number = elem[1:]
         for prefix, boxclass in self.boxkinds.iteritems():
             if elem.startswith(prefix):
                 box = boxclass()
                 break
         else:
             raise ParseError("Unknown variable type: %s" % elem)
     self._cache[elem] = box
     box._str = elem
     return box
Ejemplo n.º 9
0
 def add_op_to_short(self, shortop):
     if shortop.res in self.produced_short_boxes:
         return  # already added due to dependencies
     self.boxes_in_production[shortop.res] = None
     try:
         if isinstance(shortop, CompoundOp):
             lst = shortop.flatten(self, [])
             if len(lst) == 0:
                 return None
             else:
                 index = self._pick_op_index(lst)
                 pop = lst[index]
                 for i in range(len(lst)):
                     if i == index:
                         continue
                     opnum = OpHelpers.same_as_for_type(shortop.res.type)
                     new_name = ResOperation(opnum, [shortop.res])
                     assert lst[i].short_op is not pop.short_op
                     orig_op = lst[i].short_op.res
                     lst[i].short_op.res = new_name
                     lst[i].short_op.orig_op = orig_op
                     lst[i].invented_name = True
                     self.produced_short_boxes[new_name] = lst[i]
         else:
             pop = shortop.add_op_to_short(self)
         if pop is None:
             return
         self.produced_short_boxes[shortop.res] = pop
     finally:
         del self.boxes_in_production[shortop.res]
     return pop
Ejemplo n.º 10
0
    def optimize_call_pure(self, op, start_index=0):
        # Step 1: check if all arguments are constant
        for i in range(start_index, op.numargs()):
            self.optimizer.force_box(op.getarg(i))
            # XXX hack to ensure that virtuals that are
            #     constant are presented that way
        result = self._can_optimize_call_pure(op, start_index=start_index)
        if result is not None:
            # this removes a CALL_PURE with all constant arguments.
            self.make_constant(op, result)
            self.last_emitted_operation = REMOVED
            return

        # Step 2: check if all arguments are the same as a previous
        # CALL_PURE.
        for pos in self.call_pure_positions:
            old_op = self.optimizer._newoperations[pos]
            if self.optimize_call_pure_old(op, old_op, start_index):
                return
        if self.extra_call_pure:
            for i, old_op in enumerate(self.extra_call_pure):
                if self.optimize_call_pure_old(op, old_op, start_index):
                    if isinstance(old_op, PreambleOp):
                        old_op = self.optimizer.force_op_from_preamble(old_op)
                        self.extra_call_pure[i] = old_op
                    return

        # replace CALL_PURE with just CALL (but keep COND_CALL_VALUE)
        if start_index == 0:
            opnum = OpHelpers.call_for_descr(op.getdescr())
            newop = self.optimizer.replace_op_with(op, opnum)
        else:
            newop = op
        return self.emit_result(CallPureOptimizationResult(self, newop))
Ejemplo n.º 11
0
    def _optimize_call_arrayop(self, op, source_box, dest_box,
                               source_start_box, dest_start_box, length_box):
        length = self.get_constant_box(length_box)
        if length and length.getint() == 0:
            return True  # 0-length arraycopy or arraymove

        source_info = getptrinfo(source_box)
        dest_info = getptrinfo(dest_box)
        source_start_box = self.get_constant_box(source_start_box)
        dest_start_box = self.get_constant_box(dest_start_box)
        extrainfo = op.getdescr().get_extra_info()
        if (source_start_box and dest_start_box and length and
            ((dest_info and dest_info.is_virtual()) or length.getint() <= 8)
                and ((source_info and source_info.is_virtual())
                     or length.getint() <= 8)
                and extrainfo.single_write_descr_array
                is not None):  #<-sanity check
            source_start = source_start_box.getint()
            dest_start = dest_start_box.getint()
            arraydescr = extrainfo.single_write_descr_array
            if arraydescr.is_array_of_structs():
                return False  # not supported right now

            index_current = 0
            index_delta = +1
            index_stop = length.getint()
            if (source_box is dest_box and  # ARRAYMOVE only
                    source_start < dest_start):  # iterate in reverse order
                index_current = index_stop - 1
                index_delta = -1
                index_stop = -1

            # XXX fish fish fish
            while index_current != index_stop:
                index = index_current
                index_current += index_delta
                assert index >= 0
                if source_info and source_info.is_virtual():
                    val = source_info.getitem(arraydescr, index + source_start)
                else:
                    opnum = OpHelpers.getarrayitem_for_descr(arraydescr)
                    newop = ResOperation(
                        opnum, [source_box,
                                ConstInt(index + source_start)],
                        descr=arraydescr)
                    self.optimizer.send_extra_operation(newop)
                    val = newop
                if val is None:
                    continue
                if dest_info and dest_info.is_virtual():
                    dest_info.setitem(arraydescr, index + dest_start,
                                      get_box_replacement(dest_box), val)
                else:
                    newop = ResOperation(
                        rop.SETARRAYITEM_GC,
                        [dest_box, ConstInt(index + dest_start), val],
                        descr=arraydescr)
                    self.optimizer.send_extra_operation(newop)
            return True
        return False
Ejemplo n.º 12
0
 def propagate_all_forward(self, inputargs, ops, call_pure_results=None,
                           rename_inputargs=True, flush=True):
     if rename_inputargs:
         newargs = []
         for inparg in inputargs:
             new_arg = OpHelpers.inputarg_from_tp(inparg.type)
             inparg.set_forwarded(new_arg)
             newargs.append(new_arg)
         self.init_inparg_dict_from(newargs)
     else:
         newargs = inputargs
     self.call_pure_results = call_pure_results
     if ops[-1].getopnum() in (rop.FINISH, rop.JUMP):
         last = len(ops) - 1
         extra_jump = True
     else:
         extra_jump = False
         last = len(ops)
     for i in range(last):
         self._really_emitted_operation = None
         self.first_optimization.propagate_forward(ops[i])
     # accumulate counters
     if flush:
         self.flush()
     if extra_jump:
         self.first_optimization.propagate_forward(ops[-1])
     self.resumedata_memo.update_counters(self.metainterp_sd.profiler)
     
     return (BasicLoopInfo(newargs, self.quasi_immutable_deps),
             self._newoperations)
Ejemplo n.º 13
0
    def optimize_call_pure(self, op, start_index=0):
        # Step 1: check if all arguments are constant
        for i in range(start_index, op.numargs()):
            self.optimizer.force_box(op.getarg(i))
            # XXX hack to ensure that virtuals that are
            #     constant are presented that way
        result = self._can_optimize_call_pure(op, start_index=start_index)
        if result is not None:
            # this removes a CALL_PURE with all constant arguments.
            self.make_constant(op, result)
            self.last_emitted_operation = REMOVED
            return

        # Step 2: check if all arguments are the same as a previous
        # CALL_PURE.
        for pos in self.call_pure_positions:
            old_op = self.optimizer._newoperations[pos]
            if self.optimize_call_pure_old(op, old_op, start_index):
                return
        if self.extra_call_pure:
            for i, old_op in enumerate(self.extra_call_pure):
                if self.optimize_call_pure_old(op, old_op, start_index):
                    if isinstance(old_op, PreambleOp):
                        old_op = self.optimizer.force_op_from_preamble(old_op)
                        self.extra_call_pure[i] = old_op
                    return

        # replace CALL_PURE with just CALL (but keep COND_CALL_VALUE)
        if start_index == 0:
            opnum = OpHelpers.call_for_descr(op.getdescr())
            newop = self.optimizer.replace_op_with(op, opnum)
        else:
            newop = op
        return self.emit_result(CallPureOptimizationResult(self, newop))
Ejemplo n.º 14
0
    def optimize_CALL_PURE_I(self, op):
        # Step 1: check if all arguments are constant
        for arg in op.getarglist():
            self.optimizer.force_box(arg)
            # XXX hack to ensure that virtuals that are
            #     constant are presented that way
        result = self._can_optimize_call_pure(op)
        if result is not None:
            # this removes a CALL_PURE with all constant arguments.
            self.make_constant(op, result)
            self.last_emitted_operation = REMOVED
            return

        # Step 2: check if all arguments are the same as a previous
        # CALL_PURE.
        for pos in self.call_pure_positions:
            old_op = self.optimizer._newoperations[pos]
            if self.optimize_call_pure(op, old_op):
                return
        if self.extra_call_pure:
            for i, old_op in enumerate(self.extra_call_pure):
                if self.optimize_call_pure(op, old_op):
                    if isinstance(old_op, PreambleOp):
                        old_op = self.optimizer.force_op_from_preamble(old_op)
                        self.extra_call_pure[i] = old_op
                    return

        # replace CALL_PURE with just CALL
        opnum = OpHelpers.call_for_descr(op.getdescr())
        newop = self.optimizer.replace_op_with(op, opnum)
        self.emit_operation(newop)
        self.call_pure_positions.append(len(self.optimizer._newoperations) - 1)
Ejemplo n.º 15
0
 def rewrite(self, operations):
     # we can only remember one malloc since the next malloc can possibly
     # collect; but we can try to collapse several known-size mallocs into
     # one, both for performance and to reduce the number of write
     # barriers.  We do this on each "basic block" of operations, which in
     # this case means between CALLs or unknown-size mallocs.
     #
     operations = self.remove_bridge_exception(operations)
     for i in range(len(operations)):
         op = operations[i]
         assert op.get_forwarded() is None
         if op.getopnum() == rop.DEBUG_MERGE_POINT:
             continue
         # ---------- GETFIELD_GC ----------
         if op.getopnum() in (rop.GETFIELD_GC_I, rop.GETFIELD_GC_F,
                              rop.GETFIELD_GC_R):
             self.handle_getfield_gc(op)
             continue
         # ---------- turn NEWxxx into CALL_MALLOC_xxx ----------
         if op.is_malloc():
             self.handle_malloc_operation(op)
             continue
         if (op.is_guard() or
                 self.could_merge_with_next_guard(op, i, operations)):
             self.emit_pending_zeros()
         elif op.can_malloc():
             self.emitting_an_operation_that_can_collect()
         elif op.getopnum() == rop.LABEL:
             self.emitting_an_operation_that_can_collect()
             self._known_lengths.clear()
         # ---------- write barriers ----------
         if self.gc_ll_descr.write_barrier_descr is not None:
             if op.getopnum() == rop.SETFIELD_GC:
                 self.consider_setfield_gc(op)
                 self.handle_write_barrier_setfield(op)
                 continue
             if op.getopnum() == rop.SETINTERIORFIELD_GC:
                 self.handle_write_barrier_setinteriorfield(op)
                 continue
             if op.getopnum() == rop.SETARRAYITEM_GC:
                 self.consider_setarrayitem_gc(op)
                 self.handle_write_barrier_setarrayitem(op)
                 continue
         else:
             # this is dead code, but in case we have a gc that does
             # not have a write barrier and does not zero memory, we would
             # need to clal it
             if op.getopnum() == rop.SETFIELD_GC:
                 self.consider_setfield_gc(op)
             elif op.getopnum() == rop.SETARRAYITEM_GC:
                 self.consider_setarrayitem_gc(op)
         # ---------- call assembler -----------
         if OpHelpers.is_call_assembler(op.getopnum()):
             self.handle_call_assembler(op)
             continue
         if op.getopnum() == rop.JUMP or op.getopnum() == rop.FINISH:
             self.emit_pending_zeros()
         #
         self.emit_op(op)
     return self._newops
Ejemplo n.º 16
0
 def add_op_to_short(self, shortop):
     if shortop.res in self.produced_short_boxes:
         return # already added due to dependencies
     self.boxes_in_production[shortop.res] = None
     try:
         if isinstance(shortop, CompoundOp):
             lst = shortop.flatten(self, [])
             if len(lst) == 0:
                 return None
             else:
                 index = self._pick_op_index(lst)
                 pop = lst[index]
                 for i in range(len(lst)):
                     if i == index:
                         continue
                     opnum = OpHelpers.same_as_for_type(shortop.res.type)
                     new_name = ResOperation(opnum, [shortop.res])
                     assert lst[i].short_op is not pop.short_op
                     orig_op = lst[i].short_op.res
                     lst[i].short_op.res = new_name
                     lst[i].short_op.orig_op = orig_op
                     lst[i].invented_name = True
                     self.produced_short_boxes[new_name] = lst[i]
         else:
             pop = shortop.add_op_to_short(self)
         if pop is None:
             return
         self.produced_short_boxes[shortop.res] = pop
     finally:
         del self.boxes_in_production[shortop.res]
     return pop
Ejemplo n.º 17
0
    def optimize_CALL_PURE_I(self, op):
        # Step 1: check if all arguments are constant
        for arg in op.getarglist():
            self.optimizer.force_box(arg)
            # XXX hack to ensure that virtuals that are
            #     constant are presented that way
        result = self._can_optimize_call_pure(op)
        if result is not None:
            # this removes a CALL_PURE with all constant arguments.
            self.make_constant(op, result)
            self.last_emitted_operation = REMOVED
            return

        # Step 2: check if all arguments are the same as a previous
        # CALL_PURE.
        for pos in self.call_pure_positions:
            old_op = self.optimizer._newoperations[pos]
            if self.optimize_call_pure(op, old_op):
                return
        if self.extra_call_pure:
            for i, old_op in enumerate(self.extra_call_pure):
                if self.optimize_call_pure(op, old_op):
                    if isinstance(old_op, PreambleOp):
                        old_op = self.optimizer.force_op_from_preamble(old_op)
                        self.extra_call_pure[i] = old_op
                    return

        # replace CALL_PURE with just CALL
        opnum = OpHelpers.call_for_descr(op.getdescr())
        newop = self.optimizer.replace_op_with(op, opnum)
        self.emit_operation(newop)
        self.call_pure_positions.append(
            len(self.optimizer._newoperations) - 1)
Ejemplo n.º 18
0
 def inputarg_for_var(self, elem):
     try:
         return self._cache[elem]
     except KeyError:
         pass
     if elem[0] in 'ifrpv':
         box = OpHelpers.inputarg_from_tp(elem[0])
         number = elem[1:]
         if elem.startswith('v'):
             pattern = re.compile('.*\[(\d+)x(i|f)(\d+)\]')
             match = pattern.match(elem)
             if match:
                 box.datatype = match.group(2)[0]
                 box.bytesize = int(match.group(3)) // 8
                 box.count = int(match.group(1))
                 box.signed == item_type == 'i'
                 number = elem[1:elem.find('[')]
     else:
         number = elem[1:]
         for prefix, boxclass in self.boxkinds.iteritems():
             if elem.startswith(prefix):
                 box = boxclass()
                 break
         else:
             raise ParseError("Unknown variable type: %s" % elem)
     self._cache[elem] = box
     box._str = elem
     return box
Ejemplo n.º 19
0
 def optimize_COND_CALL(self, op):
     arg = op.getarg(0)
     b = self.getintbound(arg)
     if b.is_constant():
         if b.getint() == 0:
             self.last_emitted_operation = REMOVED
             return
         opnum = OpHelpers.call_for_type(op.type)
         op = op.copy_and_change(opnum, args=op.getarglist()[1:])
     return self.emit(op)
Ejemplo n.º 20
0
def unpack_from_vector(state, arg, index, count):
    """ Extract parts of the vector box into another vector box """
    assert count > 0
    assert index + count <= arg.count
    args = [arg, ConstInt(index), ConstInt(count)]
    vecop = OpHelpers.create_vec_unpack(arg.type, args, arg.bytesize,
                                        arg.signed, count)
    state.costmodel.record_vector_unpack(arg, index, count)
    state.oplist.append(vecop)
    return vecop
Ejemplo n.º 21
0
 def produce_short_preamble_ops(self, structbox, descr, index, optimizer, shortboxes):
     if self._fields is None:
         return
     if descr.get_index() >= len(self._fields):
         # we don't know about this item
         return
     op = optimizer.get_box_replacement(self._fields[descr.get_index()])
     opnum = OpHelpers.getfield_for_descr(descr)
     getfield_op = ResOperation(opnum, [structbox], descr=descr)
     shortboxes.add_heap_op(op, getfield_op)
Ejemplo n.º 22
0
 def add_op_to_short(self, sb):
     op = self.res
     arglist = []
     for arg in op.getarglist():
         newarg = sb.produce_arg(arg)
         if newarg is None:
             return None
         arglist.append(newarg)
     opnum = OpHelpers.call_loopinvariant_for_descr(op.getdescr())
     return ProducedShortOp(self, op.copy_and_change(opnum, args=arglist))
Ejemplo n.º 23
0
 def add_op_to_short(self, sb):
     op = self.res
     arglist = []
     for arg in op.getarglist():
         newarg = sb.produce_arg(arg)
         if newarg is None:
             return None
         arglist.append(newarg)
     opnum = OpHelpers.call_loopinvariant_for_descr(op.getdescr())
     return ProducedShortOp(self, op.copy_and_change(opnum, args=arglist))
Ejemplo n.º 24
0
 def optimize_COND_CALL(self, op):
     arg = op.getarg(0)
     b = self.getintbound(arg)
     if b.is_constant():
         if b.getint() == 0:
             self.last_emitted_operation = REMOVED
             return
         opnum = OpHelpers.call_for_type(op.type)
         op = op.copy_and_change(opnum, args=op.getarglist()[1:])
     self.emit_operation(op)
Ejemplo n.º 25
0
 def optimize_COND_CALL_VALUE_I(self, op):
     # look if we know the nullness of the first argument
     info = self.getnullness(op.getarg(0))
     if info == INFO_NONNULL:
         self.make_equal_to(op, op.getarg(0))
         self.last_emitted_operation = REMOVED
         return
     if info == INFO_NULL:
         opnum = OpHelpers.call_pure_for_type(op.type)
         op = self.replace_op_with(op, opnum, args=op.getarglist()[1:])
     return self.emit(op)
Ejemplo n.º 26
0
 def optimize_COND_CALL_VALUE_I(self, op):
     # look if we know the nullness of the first argument
     info = self.getnullness(op.getarg(0))
     if info == INFO_NONNULL:
         self.make_equal_to(op, op.getarg(0))
         self.last_emitted_operation = REMOVED
         return
     if info == INFO_NULL:
         opnum = OpHelpers.call_pure_for_type(op.type)
         op = self.replace_op_with(op, opnum, args=op.getarglist()[1:])
     return self.emit(op)
Ejemplo n.º 27
0
def unpack_from_vector(state, arg, index, count):
    """ Extract parts of the vector box into another vector box """
    assert count > 0
    vecinfo = forwarded_vecinfo(arg)
    assert index + count <= vecinfo.count
    args = [arg, ConstInt(index), ConstInt(count)]
    vecop = OpHelpers.create_vec_unpack(arg.type, args, vecinfo.bytesize,
                                        vecinfo.signed, count)
    state.costmodel.record_vector_unpack(arg, index, count)
    state.append_to_oplist(vecop)
    return vecop
Ejemplo n.º 28
0
 def produce_short_preamble_ops(self, structbox, fielddescr, index, optimizer,
                                shortboxes):
     if self._fields is None:
         return
     if fielddescr.get_index() >= len(self._fields):
         # we don't know about this item
         return
     op = optimizer.get_box_replacement(self._fields[fielddescr.get_index()])
     opnum = OpHelpers.getfield_for_descr(fielddescr)
     getfield_op = ResOperation(opnum, [structbox], descr=fielddescr)
     shortboxes.add_heap_op(op, getfield_op)
Ejemplo n.º 29
0
def unpack_from_vector(state, arg, index, count):
    """ Extract parts of the vector box into another vector box """
    assert count > 0
    vecinfo = forwarded_vecinfo(arg)
    assert index + count <= vecinfo.count
    args = [arg, ConstInt(index), ConstInt(count)]
    vecop = OpHelpers.create_vec_unpack(arg.type, args, vecinfo.bytesize,
                                        vecinfo.signed, count)
    state.costmodel.record_vector_unpack(arg, index, count)
    state.append_to_oplist(vecop)
    return vecop
Ejemplo n.º 30
0
 def accumulate_prepare(self, state):
     vec_reg_size = state.vec_reg_size
     for pack in self.packs:
         if not pack.is_accumulating():
             continue
         if pack.leftmost().is_guard():
             # guard breaks dependencies, thus it is an accumulation pack
             continue
         for i,node in enumerate(pack.operations):
             op = node.getoperation()
             state.accumulation[op] = pack
         assert isinstance(pack, AccumPack)
         datatype = pack.getdatatype()
         bytesize = pack.getbytesize()
         count = vec_reg_size // bytesize
         signed = datatype == 'i'
         oplist = state.invariant_oplist
         # reset the box to zeros or ones
         if pack.reduce_init() == 0:
             vecop = OpHelpers.create_vec(datatype, bytesize, signed, count)
             oplist.append(vecop)
             vecop = VecOperation(rop.VEC_INT_XOR, [vecop, vecop],
                                  vecop, count)
             oplist.append(vecop)
         elif pack.reduce_init() == 1:
             # multiply is only supported by floats
             vecop = OpHelpers.create_vec_expand(ConstFloat(1.0), bytesize,
                                                 signed, count)
             oplist.append(vecop)
         else:
             raise NotImplementedError("cannot handle %s" % pack.operator)
         # pack the scalar value
         args = [vecop, pack.getleftmostseed(), ConstInt(0), ConstInt(1)]
         vecop = OpHelpers.create_vec_pack(datatype, args, bytesize,
                                           signed, count)
         oplist.append(vecop)
         seed = pack.getleftmostseed()
         state.accumulation[seed] = pack
         # rename the variable with the box
         state.setvector_of_box(seed, 0, vecop) # prevent it from expansion
         state.renamer.start_renaming(seed, vecop)
Ejemplo n.º 31
0
Archivo: compile.py Proyecto: Mu-L/pypy
def compile_tmp_callback(cpu,
                         jitdriver_sd,
                         greenboxes,
                         redargtypes,
                         memory_manager=None):
    """Make a LoopToken that corresponds to assembler code that just
    calls back the interpreter.  Used temporarily: a fully compiled
    version of the code may end up replacing it.
    """
    jitcell_token = make_jitcell_token(jitdriver_sd)
    #
    # record the target of a temporary callback to the interpreter
    jl.tmp_callback(jitcell_token)
    #
    nb_red_args = jitdriver_sd.num_red_args
    assert len(redargtypes) == nb_red_args
    inputargs = []
    for kind in redargtypes:
        if kind == history.INT:
            box = InputArgInt()
        elif kind == history.REF:
            box = InputArgRef()
        elif kind == history.FLOAT:
            box = InputArgFloat()
        else:
            raise AssertionError
        inputargs.append(box)
    k = jitdriver_sd.portal_runner_adr
    funcbox = history.ConstInt(adr2int(k))
    callargs = [funcbox] + greenboxes + inputargs
    #

    jd = jitdriver_sd
    opnum = OpHelpers.call_for_descr(jd.portal_calldescr)
    call_op = ResOperation(opnum, callargs, descr=jd.portal_calldescr)
    if call_op.type != 'v' is not None:
        finishargs = [call_op]
    else:
        finishargs = []
    #
    faildescr = jitdriver_sd.propagate_exc_descr
    operations = [
        call_op,
        ResOperation(rop.GUARD_NO_EXCEPTION, [], descr=faildescr),
        ResOperation(rop.FINISH, finishargs, descr=jd.portal_finishtoken)
    ]
    operations[1].setfailargs([])
    operations = get_deep_immutable_oplist(operations)
    cpu.compile_loop(inputargs, operations, jitcell_token, log=False)

    if memory_manager is not None:  # for tests
        memory_manager.keep_loop_alive(jitcell_token)
    return jitcell_token
Ejemplo n.º 32
0
 def produce_short_preamble_ops(self, structbox, descr, index, optimizer, shortboxes):
     if self._items is None:
         return
     if index >= len(self._items):
         # we don't know about this item
         return
     item = self._items[index]
     if item is not None:
         op = optimizer.get_box_replacement(item)
         opnum = OpHelpers.getarrayitem_for_descr(descr)
         getarrayitem_op = ResOperation(opnum, [structbox, ConstInt(index)], descr=descr)
         shortboxes.add_heap_op(op, getarrayitem_op)
Ejemplo n.º 33
0
 def create_short_inputargs(self, label_args):
     return self.short_inputargs
     short_inpargs = []
     for i in range(len(label_args)):
         inparg = self.produced_short_boxes.get(label_args[i], None)
         if inparg is None:
             renamed = OpHelpers.inputarg_from_tp(label_args[i].type)
             short_inpargs.append(renamed)
         else:
             assert isinstance(inparg.short_op, ShortInputArg)
             short_inpargs.append(inparg.preamble_op)
     return short_inpargs
Ejemplo n.º 34
0
 def create_short_inputargs(self, label_args):
     return self.short_inputargs
     short_inpargs = []
     for i in range(len(label_args)):
         inparg = self.produced_short_boxes.get(label_args[i], None)
         if inparg is None:
             renamed = OpHelpers.inputarg_from_tp(label_args[i].type)
             short_inpargs.append(renamed)
         else:
             assert isinstance(inparg.short_op, ShortInputArg)
             short_inpargs.append(inparg.preamble_op)
     return short_inpargs
Ejemplo n.º 35
0
 def add_op_to_short(self, sb):
     op = self.res
     arglist = []
     for arg in op.getarglist():
         newarg = sb.produce_arg(arg)
         if newarg is None:
             return None
         arglist.append(newarg)
     if rop.is_call(op.opnum):
         opnum = OpHelpers.call_pure_for_descr(op.getdescr())
     else:
         opnum = op.getopnum()
     return ProducedShortOp(self, op.copy_and_change(opnum, args=arglist))
Ejemplo n.º 36
0
 def add_op_to_short(self, sb):
     op = self.res
     arglist = []
     for arg in op.getarglist():
         newarg = sb.produce_arg(arg)
         if newarg is None:
             return None
         arglist.append(newarg)
     if rop.is_call(op.opnum):
         opnum = OpHelpers.call_pure_for_descr(op.getdescr())
     else:
         opnum = op.getopnum()
     return ProducedShortOp(self, op.copy_and_change(opnum, args=arglist))
Ejemplo n.º 37
0
 def produce_short_preamble_ops(self, structbox, descr, index, optimizer,
                                shortboxes):
     if self._items is None:
         return
     if index >= len(self._items):
         # we don't know about this item
         return
     item = self._items[index]
     if item is not None:
         op = optimizer.get_box_replacement(item)
         opnum = OpHelpers.getarrayitem_for_descr(descr)
         getarrayitem_op = ResOperation(
             opnum, [structbox, ConstInt(index)], descr=descr)
         shortboxes.add_heap_op(op, getarrayitem_op)
Ejemplo n.º 38
0
    def protect_speculative_operation(self, op):
        """When constant-folding a pure operation that reads memory from
        a gcref, make sure that the gcref is non-null and of a valid type.
        Otherwise, raise SpeculativeError.  This should only occur when
        unrolling and optimizing the unrolled loop.  Note that if
        cpu.supports_guard_gc_type is false, we can't really do this
        check at all, but then we don't unroll in that case.
        """
        opnum = op.getopnum()
        cpu = self.cpu

        if OpHelpers.is_pure_getfield(opnum, op.getdescr()):
            fielddescr = op.getdescr()
            ref = self.get_constant_box(op.getarg(0)).getref_base()
            cpu.protect_speculative_field(ref, fielddescr)
            return

        elif (opnum == rop.GETARRAYITEM_GC_PURE_I or
              opnum == rop.GETARRAYITEM_GC_PURE_R or
              opnum == rop.GETARRAYITEM_GC_PURE_F or
              opnum == rop.ARRAYLEN_GC):
            arraydescr = op.getdescr()
            array = self.get_constant_box(op.getarg(0)).getref_base()
            cpu.protect_speculative_array(array, arraydescr)
            if opnum == rop.ARRAYLEN_GC:
                return
            arraylength = cpu.bh_arraylen_gc(array, arraydescr)

        elif (opnum == rop.STRGETITEM or
              opnum == rop.STRLEN):
            string = self.get_constant_box(op.getarg(0)).getref_base()
            cpu.protect_speculative_string(string)
            if opnum == rop.STRLEN:
                return
            arraylength = cpu.bh_strlen(string)

        elif (opnum == rop.UNICODEGETITEM or
              opnum == rop.UNICODELEN):
            unicode = self.get_constant_box(op.getarg(0)).getref_base()
            cpu.protect_speculative_unicode(unicode)
            if opnum == rop.UNICODELEN:
                return
            arraylength = cpu.bh_unicodelen(unicode)

        else:
            return

        index = self.get_constant_box(op.getarg(1)).getint()
        if not (0 <= index < arraylength):
            raise SpeculativeError
Ejemplo n.º 39
0
def compile_tmp_callback(cpu, jitdriver_sd, greenboxes, redargtypes,
                         memory_manager=None):
    """Make a LoopToken that corresponds to assembler code that just
    calls back the interpreter.  Used temporarily: a fully compiled
    version of the code may end up replacing it.
    """
    jitcell_token = make_jitcell_token(jitdriver_sd)
    #
    # record the target of a temporary callback to the interpreter
    jl.tmp_callback(jitcell_token)
    #
    nb_red_args = jitdriver_sd.num_red_args
    assert len(redargtypes) == nb_red_args
    inputargs = []
    for kind in redargtypes:
        if kind == history.INT:
            box = InputArgInt()
        elif kind == history.REF:
            box = InputArgRef()
        elif kind == history.FLOAT:
            box = InputArgFloat()
        else:
            raise AssertionError
        inputargs.append(box)
    k = jitdriver_sd.portal_runner_adr
    funcbox = history.ConstInt(heaptracker.adr2int(k))
    callargs = [funcbox] + greenboxes + inputargs
    #

    jd = jitdriver_sd
    opnum = OpHelpers.call_for_descr(jd.portal_calldescr)
    call_op = ResOperation(opnum, callargs, descr=jd.portal_calldescr)
    if call_op.type != 'v' is not None:
        finishargs = [call_op]
    else:
        finishargs = []
    #
    faildescr = jitdriver_sd.propagate_exc_descr
    operations = [
        call_op,
        ResOperation(rop.GUARD_NO_EXCEPTION, [], descr=faildescr),
        ResOperation(rop.FINISH, finishargs, descr=jd.portal_finishtoken)
    ]
    operations[1].setfailargs([])
    operations = get_deep_immutable_oplist(operations)
    cpu.compile_loop(inputargs, operations, jitcell_token, log=False)

    if memory_manager is not None:    # for tests
        memory_manager.keep_loop_alive(jitcell_token)
    return jitcell_token
Ejemplo n.º 40
0
    def protect_speculative_operation(self, op):
        """When constant-folding a pure operation that reads memory from
        a gcref, make sure that the gcref is non-null and of a valid type.
        Otherwise, raise SpeculativeError.  This should only occur when
        unrolling and optimizing the unrolled loop.  Note that if
        cpu.supports_guard_gc_type is false, we can't really do this
        check at all, but then we don't unroll in that case.
        """
        opnum = op.getopnum()
        cpu = self.cpu

        if OpHelpers.is_pure_getfield(opnum, op.getdescr()):
            fielddescr = op.getdescr()
            ref = self.get_constant_box(op.getarg(0)).getref_base()
            cpu.protect_speculative_field(ref, fielddescr)
            return

        elif (opnum == rop.GETARRAYITEM_GC_PURE_I or
              opnum == rop.GETARRAYITEM_GC_PURE_R or
              opnum == rop.GETARRAYITEM_GC_PURE_F or
              opnum == rop.ARRAYLEN_GC):
            arraydescr = op.getdescr()
            array = self.get_constant_box(op.getarg(0)).getref_base()
            cpu.protect_speculative_array(array, arraydescr)
            if opnum == rop.ARRAYLEN_GC:
                return
            arraylength = cpu.bh_arraylen_gc(array, arraydescr)

        elif (opnum == rop.STRGETITEM or
              opnum == rop.STRLEN):
            string = self.get_constant_box(op.getarg(0)).getref_base()
            cpu.protect_speculative_string(string)
            if opnum == rop.STRLEN:
                return
            arraylength = cpu.bh_strlen(string)

        elif (opnum == rop.UNICODEGETITEM or
              opnum == rop.UNICODELEN):
            unicode = self.get_constant_box(op.getarg(0)).getref_base()
            cpu.protect_speculative_unicode(unicode)
            if opnum == rop.UNICODELEN:
                return
            arraylength = cpu.bh_unicodelen(unicode)

        else:
            return

        index = self.get_constant_box(op.getarg(1)).getint()
        if not (0 <= index < arraylength):
            raise SpeculativeError
Ejemplo n.º 41
0
def pack_into_vector(state, tgt, tidx, src, sidx, scount):
    """ tgt = [1,2,3,4,_,_,_,_]
        src = [5,6,_,_]
        new_box = [1,2,3,4,5,6,_,_] after the operation, tidx=4, scount=2
    """
    assert sidx == 0 # restriction
    newcount = tgt.count + scount
    args = [tgt, src, ConstInt(tidx), ConstInt(scount)]
    vecop = OpHelpers.create_vec_pack(tgt.type, args, tgt.bytesize, tgt.signed, newcount)
    state.oplist.append(vecop)
    state.costmodel.record_vector_pack(src, sidx, scount)
    if not we_are_translated():
        _check_vec_pack(vecop)
    return vecop
Ejemplo n.º 42
0
def patch_new_loop_to_load_virtualizable_fields(loop, jitdriver_sd, vable):
    # XXX merge with rewriting
    vinfo = jitdriver_sd.virtualizable_info
    extra_ops = []
    inputargs = loop.inputargs
    vable_box = inputargs[jitdriver_sd.index_of_virtualizable]
    i = jitdriver_sd.num_red_args
    loop.inputargs = inputargs[:i]
    for descr in vinfo.static_field_descrs:
        assert i < len(inputargs)
        box = inputargs[i]
        opnum = OpHelpers.getfield_for_descr(descr)
        emit_op(extra_ops,
                ResOperation(opnum, [vable_box], descr))
        box.set_forwarded(extra_ops[-1])
        i += 1
    arrayindex = 0
    for descr in vinfo.array_field_descrs:
        arraylen = vinfo.get_array_length(vable, arrayindex)
        arrayop = ResOperation(rop.GETFIELD_GC_R, [vable_box], descr)
        emit_op(extra_ops, arrayop)
        arraydescr = vinfo.array_descrs[arrayindex]
        assert i + arraylen <= len(inputargs)
        for index in range(arraylen):
            opnum = OpHelpers.getarrayitem_for_descr(arraydescr)
            box = inputargs[i]
            emit_op(extra_ops,
                ResOperation(opnum,
                             [arrayop, ConstInt(index)],
                             descr=arraydescr))
            i += 1
            box.set_forwarded(extra_ops[-1])
        arrayindex += 1
    assert i == len(inputargs)
    for op in loop.operations:
        emit_op(extra_ops, op)
    loop.operations = extra_ops
Ejemplo n.º 43
0
def patch_new_loop_to_load_virtualizable_fields(loop, jitdriver_sd, vable):
    # XXX merge with rewriting
    vinfo = jitdriver_sd.virtualizable_info
    extra_ops = []
    inputargs = loop.inputargs
    vable_box = inputargs[jitdriver_sd.index_of_virtualizable]
    i = jitdriver_sd.num_red_args
    loop.inputargs = inputargs[:i]
    for descr in vinfo.static_field_descrs:
        assert i < len(inputargs)
        box = inputargs[i]
        opnum = OpHelpers.getfield_for_descr(descr)
        emit_op(extra_ops,
                ResOperation(opnum, [vable_box], descr=descr))
        box.set_forwarded(extra_ops[-1])
        i += 1
    arrayindex = 0
    for descr in vinfo.array_field_descrs:
        arraylen = vinfo.get_array_length(vable, arrayindex)
        arrayop = ResOperation(rop.GETFIELD_GC_R, [vable_box], descr=descr)
        emit_op(extra_ops, arrayop)
        arraydescr = vinfo.array_descrs[arrayindex]
        assert i + arraylen <= len(inputargs)
        for index in range(arraylen):
            opnum = OpHelpers.getarrayitem_for_descr(arraydescr)
            box = inputargs[i]
            emit_op(extra_ops,
                ResOperation(opnum,
                             [arrayop, ConstInt(index)],
                             descr=arraydescr))
            i += 1
            box.set_forwarded(extra_ops[-1])
        arrayindex += 1
    assert i == len(inputargs)
    for op in loop.operations:
        emit_op(extra_ops, op)
    loop.operations = extra_ops
Ejemplo n.º 44
0
    def _optimize_CALL_ARRAYCOPY(self, op):
        length = self.get_constant_box(op.getarg(5))
        if length and length.getint() == 0:
            return None  # 0-length arraycopy

        source_info = self.getptrinfo(op.getarg(1))
        dest_info = self.getptrinfo(op.getarg(2))
        source_start_box = self.get_constant_box(op.getarg(3))
        dest_start_box = self.get_constant_box(op.getarg(4))
        extrainfo = op.getdescr().get_extra_info()
        if (source_start_box and dest_start_box and length and
            ((dest_info and dest_info.is_virtual()) or length.getint() <= 8)
                and ((source_info and source_info.is_virtual())
                     or length.getint() <= 8)
                and extrainfo.single_write_descr_array
                is not None):  #<-sanity check
            source_start = source_start_box.getint()
            dest_start = dest_start_box.getint()
            arraydescr = extrainfo.single_write_descr_array
            if arraydescr.is_array_of_structs():
                return self.emit(op)  # not supported right now

            # XXX fish fish fish
            for index in range(length.getint()):
                if source_info and source_info.is_virtual():
                    val = source_info.getitem(arraydescr, index + source_start)
                else:
                    opnum = OpHelpers.getarrayitem_for_descr(arraydescr)
                    newop = ResOperation(
                        opnum, [op.getarg(1),
                                ConstInt(index + source_start)],
                        descr=arraydescr)
                    self.optimizer.send_extra_operation(newop)
                    val = newop
                if val is None:
                    continue
                if dest_info and dest_info.is_virtual():
                    dest_info.setitem(arraydescr, index + dest_start,
                                      self.get_box_replacement(op.getarg(2)),
                                      val)
                else:
                    newop = ResOperation(
                        rop.SETARRAYITEM_GC,
                        [op.getarg(2),
                         ConstInt(index + dest_start), val],
                        descr=arraydescr)
                    self.optimizer.send_extra_operation(newop)
            return None
        return self.emit(op)
Ejemplo n.º 45
0
def pack_into_vector(state, tgt, tidx, src, sidx, scount):
    """ tgt = [1,2,3,4,_,_,_,_]
        src = [5,6,_,_]
        new_box = [1,2,3,4,5,6,_,_] after the operation, tidx=4, scount=2
    """
    assert sidx == 0 # restriction
    vecinfo = forwarded_vecinfo(tgt)
    newcount = vecinfo.count + scount
    args = [tgt, src, ConstInt(tidx), ConstInt(scount)]
    vecop = OpHelpers.create_vec_pack(tgt.type, args, vecinfo.bytesize, vecinfo.signed, newcount)
    state.oplist.append(vecop)
    state.costmodel.record_vector_pack(src, sidx, scount)
    if not we_are_translated():
        _check_vec_pack(vecop)
    return vecop
Ejemplo n.º 46
0
    def _optimize_CALL_ARRAYCOPY(self, op):
        length = self.get_constant_box(op.getarg(5))
        if length and length.getint() == 0:
            return True # 0-length arraycopy

        source_info = self.getptrinfo(op.getarg(1))
        dest_info = self.getptrinfo(op.getarg(2))
        source_start_box = self.get_constant_box(op.getarg(3))
        dest_start_box = self.get_constant_box(op.getarg(4))
        extrainfo = op.getdescr().get_extra_info()
        if (source_start_box and dest_start_box
            and length and ((dest_info and dest_info.is_virtual()) or
                            length.getint() <= 8) and
            ((source_info and source_info.is_virtual()) or length.getint() <= 8)
            and len(extrainfo.write_descrs_arrays) == 1):   # <-sanity check
            source_start = source_start_box.getint()
            dest_start = dest_start_box.getint()
            arraydescr = extrainfo.write_descrs_arrays[0]
            if arraydescr.is_array_of_structs():
                return False       # not supported right now

            # XXX fish fish fish
            for index in range(length.getint()):
                if source_info and source_info.is_virtual():
                    val = source_info.getitem(arraydescr, index + source_start)
                else:
                    opnum = OpHelpers.getarrayitem_for_descr(arraydescr)
                    newop = ResOperation(opnum,
                                      [op.getarg(1),
                                       ConstInt(index + source_start)],
                                       descr=arraydescr)
                    self.optimizer.send_extra_operation(newop)
                    val = newop
                if val is None:
                    continue
                if dest_info and dest_info.is_virtual():
                    dest_info.setitem(arraydescr, index + dest_start,
                                      self.get_box_replacement(op.getarg(2)),
                                      val)
                else:
                    newop = ResOperation(rop.SETARRAYITEM_GC,
                                         [op.getarg(2),
                                          ConstInt(index + dest_start),
                                          val],
                                         descr=arraydescr)
                    self.emit_operation(newop)
            return True
        return False
Ejemplo n.º 47
0
 def produce_short_preamble_ops(self, structbox, fielddescr, index,
                                optimizer, shortboxes):
     if self._fields is None:
         return
     if fielddescr.get_index() >= len(self._fields):
         # we don't know about this item
         return
     op = get_box_replacement(self._fields[fielddescr.get_index()])
     if op is None:
         # XXX same bug as in serialize_opt:
         # op should never be None, because that's an invariant violation in
         # AbstractCachedEntry. But it still seems to happen when the info
         # is attached to a Constant. At least we shouldn't crash.
         return
     opnum = OpHelpers.getfield_for_descr(fielddescr)
     getfield_op = ResOperation(opnum, [structbox], descr=fielddescr)
     shortboxes.add_heap_op(op, getfield_op)
Ejemplo n.º 48
0
 def optimize_call_pure_old(self, op, old_op, start_index):
     if op.getdescr() is not old_op.getdescr():
         return False
     # this will match a call_pure and a cond_call_value with
     # the same function and arguments
     old_start_index = OpHelpers.is_cond_call_value(old_op.opnum)
     if self._same_args(old_op, op, old_start_index, start_index):
         # all identical
         # this removes a CALL_PURE that has the same (non-constant)
         # arguments as a previous CALL_PURE.
         if isinstance(old_op, PreambleOp):
             # xxx obscure, it's dealt with in the caller
             old_op = old_op.op
         self.make_equal_to(op, old_op)
         self.last_emitted_operation = REMOVED
         return True
     return False
Ejemplo n.º 49
0
 def ensure_unpacked(self, index, arg):
     if arg in self.seen or arg.is_vector():
         return arg
     (pos, var) = self.getvector_of_box(arg)
     if var:
         if var in self.invariant_vector_vars:
             return arg
         if arg in self.accumulation:
             return arg
         args = [var, ConstInt(pos), ConstInt(1)]
         vecop = OpHelpers.create_vec_unpack(var.type, args, var.bytesize,
                                             var.signed, 1)
         self.renamer.start_renaming(arg, vecop)
         self.seen[vecop] = None
         self.costmodel.record_vector_unpack(var, pos, 1)
         self.oplist.append(vecop)
         return vecop
     return arg
Ejemplo n.º 50
0
    def optimize_CALL_LOOPINVARIANT_I(self, op):
        arg = op.getarg(0)
        # 'arg' must be a Const, because residual_call in codewriter
        # expects a compile-time constant
        assert isinstance(arg, Const)
        key = make_hashable_int(arg.getint())

        resvalue = self.loop_invariant_results.get(key, None)
        if resvalue is not None:
            resvalue = self.optimizer.force_op_from_preamble(resvalue)
            self.loop_invariant_results[key] = resvalue
            self.make_equal_to(op, resvalue)
            self.last_emitted_operation = REMOVED
            return
        # change the op to be a normal call, from the backend's point of view
        # there is no reason to have a separate operation for this
        newop = self.replace_op_with(op, OpHelpers.call_for_descr(op.getdescr()))
        return self.emit_result(CallLoopinvariantOptimizationResult(self, newop, op))
Ejemplo n.º 51
0
 def ensure_unpacked(self, index, arg):
     if arg in self.seen or arg.is_vector():
         return arg
     (pos, var) = self.getvector_of_box(arg)
     if var:
         if var in self.invariant_vector_vars:
             return arg
         if arg in self.accumulation:
             return arg
         args = [var, ConstInt(pos), ConstInt(1)]
         vecinfo = forwarded_vecinfo(var)
         vecop = OpHelpers.create_vec_unpack(var.type, args, vecinfo.bytesize,
                                             vecinfo.signed, 1)
         self.renamer.start_renaming(arg, vecop)
         self.seen[vecop] = None
         self.costmodel.record_vector_unpack(var, pos, 1)
         self.oplist.append(vecop)
         return vecop
     return arg
Ejemplo n.º 52
0
    def optimize_CALL_LOOPINVARIANT_I(self, op):
        arg = op.getarg(0)
        # 'arg' must be a Const, because residual_call in codewriter
        # expects a compile-time constant
        assert isinstance(arg, Const)
        key = make_hashable_int(arg.getint())

        resvalue = self.loop_invariant_results.get(key, None)
        if resvalue is not None:
            resvalue = self.optimizer.force_op_from_preamble(resvalue)
            self.loop_invariant_results[key] = resvalue
            self.make_equal_to(op, resvalue)
            self.last_emitted_operation = REMOVED
            return
        # change the op to be a normal call, from the backend's point of view
        # there is no reason to have a separate operation for this
        newop = self.replace_op_with(op,
                                     OpHelpers.call_for_descr(op.getdescr()))
        return self.emit_result(CallLoopinvariantOptimizationResult(self, newop, op))
Ejemplo n.º 53
0
 def optimize_call_pure_old(self, op, old_op, start_index):
     if op.getdescr() is not old_op.getdescr():
         return False
     # this will match a call_pure and a cond_call_value with
     # the same function and arguments
     j = start_index
     old_start_index = OpHelpers.is_cond_call_value(old_op.opnum)
     for i in range(old_start_index, old_op.numargs()):
         box = old_op.getarg(i)
         if not get_box_replacement(op.getarg(j)).same_box(box):
             break
         j += 1
     else:
         # all identical
         # this removes a CALL_PURE that has the same (non-constant)
         # arguments as a previous CALL_PURE.
         if isinstance(old_op, PreambleOp):
             # xxx obscure, it's dealt with in the caller
             old_op = old_op.op
         self.make_equal_to(op, old_op)
         self.last_emitted_operation = REMOVED
         return True
     return False
Ejemplo n.º 54
0
 def optimize_call_pure_old(self, op, old_op, start_index):
     if op.getdescr() is not old_op.getdescr():
         return False
     # this will match a call_pure and a cond_call_value with
     # the same function and arguments
     j = start_index
     old_start_index = OpHelpers.is_cond_call_value(old_op.opnum)
     for i in range(old_start_index, old_op.numargs()):
         box = old_op.getarg(i)
         if not self.get_box_replacement(op.getarg(j)).same_box(box):
             break
         j += 1
     else:
         # all identical
         # this removes a CALL_PURE that has the same (non-constant)
         # arguments as a previous CALL_PURE.
         if isinstance(old_op, PreambleOp):
             # xxx obscure, it's dealt with in the caller
             old_op = old_op.op
         self.make_equal_to(op, old_op)
         self.last_emitted_operation = REMOVED
         return True
     return False
Ejemplo n.º 55
0
    def produce_potential_short_preamble_ops(self, sb):
        ops = self.optimizer._newoperations
        for i, op in enumerate(ops):
            if rop.is_always_pure(op.opnum):
                sb.add_pure_op(op)
            if rop.is_ovf(op.opnum) and ops[i + 1].getopnum() == rop.GUARD_NO_OVERFLOW:
                sb.add_pure_op(op)
        for i in self.call_pure_positions:
            op = ops[i]
            # don't move call_pure_with_exception in the short preamble...
            # issue #2015

            # Also, don't move cond_call_value in the short preamble.
            # The issue there is that it's usually pointless to try to
            # because the 'value' argument is typically not a loop
            # invariant, and would really need to be in order to end up
            # in the short preamble.  Maybe the code works anyway in the
            # other rare case, but better safe than sorry and don't try.
            effectinfo = op.getdescr().get_extra_info()
            if not effectinfo.check_can_raise(ignore_memoryerror=True):
                assert rop.is_call(op.opnum)
                if not OpHelpers.is_cond_call_value(op.opnum):
                    sb.add_pure_op(op)
Ejemplo n.º 56
0
    def create_short_boxes(self, optimizer, inputargs, label_args):
        # all the potential operations that can be produced, subclasses
        # of AbstractShortOp
        self.potential_ops = OrderedDict()
        self.produced_short_boxes = {}
        # a way to produce const boxes, e.g. setfield_gc(p0, Const).
        # We need to remember those, but they don't produce any new boxes
        self.const_short_boxes = []
        self.short_inputargs = []
        for i in range(len(label_args)):
            box = label_args[i]
            renamed = OpHelpers.inputarg_from_tp(box.type)
            self.short_inputargs.append(renamed)
            self.potential_ops[box] = ShortInputArg(box, renamed)

        optimizer.produce_potential_short_preamble_ops(self)

        short_boxes = []
        self.boxes_in_production = {}

        for shortop in self.potential_ops.values():
            self.add_op_to_short(shortop)
        #
        for op, produced_op in self.produced_short_boxes.iteritems():
            short_boxes.append(produced_op)

        for short_op in self.const_short_boxes:
            getfield_op = short_op.getfield_op
            args = getfield_op.getarglist()
            preamble_arg = self.produce_arg(args[0])
            if preamble_arg is not None:
                preamble_op = getfield_op.copy_and_change(
                      getfield_op.getopnum(), [preamble_arg] + args[1:])
                produced_op = ProducedShortOp(short_op, preamble_op)
                short_boxes.append(produced_op)
        return short_boxes
Ejemplo n.º 57
0
    def create_short_boxes(self, optimizer, inputargs, label_args):
        # all the potential operations that can be produced, subclasses
        # of AbstractShortOp
        self.potential_ops = OrderedDict()
        self.produced_short_boxes = {}
        # a way to produce const boxes, e.g. setfield_gc(p0, Const).
        # We need to remember those, but they don't produce any new boxes
        self.const_short_boxes = []
        self.short_inputargs = []
        for i in range(len(label_args)):
            box = label_args[i]
            renamed = OpHelpers.inputarg_from_tp(box.type)
            self.short_inputargs.append(renamed)
            self.potential_ops[box] = ShortInputArg(box, renamed)

        optimizer.produce_potential_short_preamble_ops(self)

        short_boxes = []
        self.boxes_in_production = {}

        for shortop in self.potential_ops.values():
            self.add_op_to_short(shortop)
        #
        for op, produced_op in self.produced_short_boxes.iteritems():
            short_boxes.append(produced_op)

        for short_op in self.const_short_boxes:
            getfield_op = short_op.getfield_op
            args = getfield_op.getarglist()
            preamble_arg = self.produce_arg(args[0])
            if preamble_arg is not None:
                preamble_op = getfield_op.copy_and_change(
                    getfield_op.getopnum(), [preamble_arg] + args[1:])
                produced_op = ProducedShortOp(short_op, preamble_op)
                short_boxes.append(produced_op)
        return short_boxes