Author: Maciej Fijalkowski <fij...@gmail.com> Branch: result-in-resops Changeset: r56422:3b467df21f17 Date: 2012-07-24 13:14 +0200 http://bitbucket.org/pypy/pypy/changeset/3b467df21f17/
Log: some progress on resop specialization diff --git a/pypy/jit/backend/llgraph/runner.py b/pypy/jit/backend/llgraph/runner.py --- a/pypy/jit/backend/llgraph/runner.py +++ b/pypy/jit/backend/llgraph/runner.py @@ -9,7 +9,7 @@ from pypy.rpython.ootypesystem import ootype from pypy.rpython.llinterp import LLInterpreter from pypy.jit.metainterp import history -from pypy.jit.metainterp.history import REF, INT, FLOAT, STRUCT +from pypy.jit.metainterp.resoperation import REF, INT, FLOAT, STRUCT from pypy.jit.metainterp.warmstate import unwrap from pypy.jit.metainterp.resoperation import rop from pypy.jit.backend import model diff --git a/pypy/jit/metainterp/compile.py b/pypy/jit/metainterp/compile.py --- a/pypy/jit/metainterp/compile.py +++ b/pypy/jit/metainterp/compile.py @@ -9,7 +9,7 @@ from pypy.conftest import option from pypy.tool.sourcetools import func_with_new_name -from pypy.jit.metainterp.resoperation import ResOperation, rop, get_deep_immutable_oplist +from pypy.jit.metainterp.resoperation import rop, get_deep_immutable_oplist from pypy.jit.metainterp.history import TreeLoop, Box, History, JitCellToken, TargetToken from pypy.jit.metainterp.history import AbstractFailDescr, BoxInt from pypy.jit.metainterp.history import BoxPtr, BoxObj, BoxFloat, Const, ConstInt diff --git a/pypy/jit/metainterp/executor.py b/pypy/jit/metainterp/executor.py --- a/pypy/jit/metainterp/executor.py +++ b/pypy/jit/metainterp/executor.py @@ -5,10 +5,11 @@ from pypy.rlib.rarithmetic import ovfcheck, r_longlong, is_valid_int from pypy.rlib.rtimer import read_timestamp from pypy.rlib.unroll import unrolling_iterable -from pypy.jit.metainterp.history import BoxInt, BoxPtr, BoxFloat, check_descr -from pypy.jit.metainterp.history import INT, REF, FLOAT, VOID, AbstractDescr +from pypy.jit.metainterp.history import BoxInt, BoxPtr, BoxFloat, check_descr,\ + AbstractDescr +from pypy.jit.metainterp.resoperation import INT, REF, FLOAT, VOID from pypy.jit.metainterp import resoperation -from pypy.jit.metainterp.resoperation import rop, ResOperation +from pypy.jit.metainterp.resoperation import rop, create_resop from pypy.jit.metainterp.blackhole import BlackholeInterpreter, NULL from pypy.jit.codewriter import longlong @@ -333,6 +334,7 @@ name = 'bhimpl_' + key.lower() if hasattr(BlackholeInterpreter, name): func = make_execute_function_with_boxes( + value, key.lower(), getattr(BlackholeInterpreter, name).im_func) if func is not None: @@ -366,7 +368,7 @@ #raise AssertionError("missing %r" % (key,)) return execute_by_num_args -def make_execute_function_with_boxes(name, func): +def make_execute_function_with_boxes(opnum, name, func): # Make a wrapper for 'func'. The func is a simple bhimpl_xxx function # from the BlackholeInterpreter class. The wrapper is a new function # that receives and returns boxed values. @@ -383,7 +385,6 @@ if func.resulttype not in ('i', 'r', 'f', None): return None argtypes = unrolling_iterable(func.argtypes) - resulttype = func.resulttype # def do(cpu, _, *args): newargs = () @@ -405,12 +406,11 @@ assert not args # result = func(*newargs) - ResOperation(opnum, orig_args, result, ) + if has_descr: + return create_resop(opnum, orig_args[:-1], result, orig_args[-1]) + else: + return create_resop(opnum, orig_args, result) # - if resulttype == 'i': return BoxInt(result) - if resulttype == 'r': return BoxPtr(result) - if resulttype == 'f': return BoxFloat(result) - return None # do.func_name = 'do_' + name return do diff --git a/pypy/jit/metainterp/heapcache.py b/pypy/jit/metainterp/heapcache.py --- a/pypy/jit/metainterp/heapcache.py +++ b/pypy/jit/metainterp/heapcache.py @@ -50,11 +50,12 @@ def _output_indirection(self, box): return self.output_indirections.get(box, box) - def invalidate_caches(self, opnum, descr, argboxes): - self.mark_escaped(opnum, argboxes) - self.clear_caches(opnum, descr, argboxes) + def invalidate_caches(self, op): + self.mark_escaped(op) + self.clear_caches(op) - def mark_escaped(self, opnum, argboxes): + def mark_escaped(self, op): + opnum = op.getopnum() if opnum == rop.SETFIELD_GC: assert len(argboxes) == 2 box, valuebox = argboxes @@ -77,23 +78,22 @@ opnum != rop.MARK_OPAQUE_PTR and opnum != rop.PTR_EQ and opnum != rop.PTR_NE): - idx = 0 - for box in argboxes: - # setarrayitem_gc don't escape its first argument - if not (idx == 0 and opnum in [rop.SETARRAYITEM_GC]): - self._escape(box) - idx += 1 + op.foreach_arg(self._escape) - def _escape(self, box): - if box in self.new_boxes: - self.new_boxes[box] = False - if box in self.dependencies: - deps = self.dependencies[box] - del self.dependencies[box] + def _escape(self, opnum, idx, source): + # setarrayitem_gc don't escape its first argument + if idx == 0 and opnum == rop.SETARRAYITEM_GC: + return + if source in self.new_boxes: + self.new_boxes[source] = False + if source in self.dependencies: + deps = self.dependencies[source] + del self.dependencies[source] for dep in deps: self._escape(dep) - def clear_caches(self, opnum, descr, argboxes): + def clear_caches(self, op): + opnum = op.getopnum() if (opnum == rop.SETFIELD_GC or opnum == rop.SETARRAYITEM_GC or opnum == rop.SETFIELD_RAW or diff --git a/pypy/jit/metainterp/history.py b/pypy/jit/metainterp/history.py --- a/pypy/jit/metainterp/history.py +++ b/pypy/jit/metainterp/history.py @@ -8,19 +8,14 @@ from pypy.conftest import option -from pypy.jit.metainterp.resoperation import ResOperation, rop, AbstractValue +from pypy.jit.metainterp.resoperation import rop, AbstractValue, INT, REF,\ + FLOAT + from pypy.jit.codewriter import heaptracker, longlong import weakref # ____________________________________________________________ -INT = 'i' -REF = 'r' -FLOAT = 'f' -STRUCT = 's' -HOLE = '_' -VOID = 'v' - FAILARGS_LIMIT = 1000 def getkind(TYPE, supports_floats=True, @@ -152,6 +147,9 @@ def __repr__(self): return 'Const(%s)' % self._getrepr_() + def is_constant(self): + return True + class ConstInt(Const): type = INT @@ -799,10 +797,8 @@ self.inputargs = None self.operations = [] - def record(self, opnum, argboxes, resbox, descr=None): - op = ResOperation(opnum, argboxes, resbox, descr) + def record(self, op): self.operations.append(op) - return op def substitute_operation(self, position, opnum, argboxes, descr=None): resbox = self.operations[position].result diff --git a/pypy/jit/metainterp/optimizeopt/earlyforce.py b/pypy/jit/metainterp/optimizeopt/earlyforce.py --- a/pypy/jit/metainterp/optimizeopt/earlyforce.py +++ b/pypy/jit/metainterp/optimizeopt/earlyforce.py @@ -1,6 +1,6 @@ from pypy.jit.metainterp.optimizeopt.optimizer import Optimization from pypy.jit.metainterp.optimizeopt.vstring import VAbstractStringValue -from pypy.jit.metainterp.resoperation import rop, ResOperation +from pypy.jit.metainterp.resoperation import rop class OptEarlyForce(Optimization): def propagate_forward(self, op): diff --git a/pypy/jit/metainterp/optimizeopt/fficall.py b/pypy/jit/metainterp/optimizeopt/fficall.py --- a/pypy/jit/metainterp/optimizeopt/fficall.py +++ b/pypy/jit/metainterp/optimizeopt/fficall.py @@ -1,7 +1,7 @@ from pypy.jit.codewriter.effectinfo import EffectInfo from pypy.jit.metainterp.optimizeopt.optimizer import Optimization from pypy.jit.metainterp.optimizeopt.util import make_dispatcher_method -from pypy.jit.metainterp.resoperation import rop, ResOperation +from pypy.jit.metainterp.resoperation import rop from pypy.rlib import clibffi, libffi from pypy.rlib.debug import debug_print from pypy.rlib.libffi import Func diff --git a/pypy/jit/metainterp/optimizeopt/heap.py b/pypy/jit/metainterp/optimizeopt/heap.py --- a/pypy/jit/metainterp/optimizeopt/heap.py +++ b/pypy/jit/metainterp/optimizeopt/heap.py @@ -4,7 +4,7 @@ from pypy.jit.metainterp.optimizeopt.optimizer import Optimization, MODE_ARRAY from pypy.jit.metainterp.history import ConstInt, Const from pypy.jit.metainterp.optimizeopt.util import make_dispatcher_method -from pypy.jit.metainterp.resoperation import rop, ResOperation +from pypy.jit.metainterp.resoperation import rop from pypy.rlib.objectmodel import we_are_translated diff --git a/pypy/jit/metainterp/optimizeopt/intutils.py b/pypy/jit/metainterp/optimizeopt/intutils.py --- a/pypy/jit/metainterp/optimizeopt/intutils.py +++ b/pypy/jit/metainterp/optimizeopt/intutils.py @@ -1,6 +1,6 @@ from pypy.rlib.rarithmetic import ovfcheck, LONG_BIT, maxint, is_valid_int from pypy.rlib.objectmodel import we_are_translated -from pypy.jit.metainterp.resoperation import rop, ResOperation +from pypy.jit.metainterp.resoperation import rop, create_resop from pypy.jit.metainterp.history import BoxInt, ConstInt MAXINT = maxint MININT = -maxint - 1 diff --git a/pypy/jit/metainterp/optimizeopt/optimizer.py b/pypy/jit/metainterp/optimizeopt/optimizer.py --- a/pypy/jit/metainterp/optimizeopt/optimizer.py +++ b/pypy/jit/metainterp/optimizeopt/optimizer.py @@ -6,7 +6,7 @@ IntLowerBound, MININT, MAXINT from pypy.jit.metainterp.optimizeopt.util import (make_dispatcher_method, args_dict) -from pypy.jit.metainterp.resoperation import rop, ResOperation, AbstractResOp +from pypy.jit.metainterp.resoperation import rop, AbstractResOp from pypy.jit.metainterp.typesystem import llhelper, oohelper from pypy.tool.pairtype import extendabletype from pypy.rlib.debug import debug_start, debug_stop, debug_print diff --git a/pypy/jit/metainterp/optimizeopt/pure.py b/pypy/jit/metainterp/optimizeopt/pure.py --- a/pypy/jit/metainterp/optimizeopt/pure.py +++ b/pypy/jit/metainterp/optimizeopt/pure.py @@ -1,5 +1,5 @@ from pypy.jit.metainterp.optimizeopt.optimizer import Optimization, REMOVED -from pypy.jit.metainterp.resoperation import rop, ResOperation +from pypy.jit.metainterp.resoperation import rop from pypy.jit.metainterp.optimizeopt.util import (make_dispatcher_method, args_dict) diff --git a/pypy/jit/metainterp/optimizeopt/rewrite.py b/pypy/jit/metainterp/optimizeopt/rewrite.py --- a/pypy/jit/metainterp/optimizeopt/rewrite.py +++ b/pypy/jit/metainterp/optimizeopt/rewrite.py @@ -4,8 +4,7 @@ from pypy.jit.metainterp.optimizeopt.intutils import IntBound from pypy.jit.metainterp.optimizeopt.optimizer import * from pypy.jit.metainterp.optimizeopt.util import _findall, make_dispatcher_method -from pypy.jit.metainterp.resoperation import (opboolinvers, opboolreflex, rop, - ResOperation) +from pypy.jit.metainterp.resoperation import (opboolinvers, opboolreflex, rop) from pypy.rlib.rarithmetic import highest_bit diff --git a/pypy/jit/metainterp/optimizeopt/simplify.py b/pypy/jit/metainterp/optimizeopt/simplify.py --- a/pypy/jit/metainterp/optimizeopt/simplify.py +++ b/pypy/jit/metainterp/optimizeopt/simplify.py @@ -1,6 +1,6 @@ from pypy.jit.metainterp.optimizeopt.optimizer import Optimization from pypy.jit.metainterp.optimizeopt.util import make_dispatcher_method -from pypy.jit.metainterp.resoperation import ResOperation, rop +from pypy.jit.metainterp.resoperation import rop from pypy.jit.metainterp.history import TargetToken, JitCellToken class OptSimplify(Optimization): diff --git a/pypy/jit/metainterp/optimizeopt/unroll.py b/pypy/jit/metainterp/optimizeopt/unroll.py --- a/pypy/jit/metainterp/optimizeopt/unroll.py +++ b/pypy/jit/metainterp/optimizeopt/unroll.py @@ -7,7 +7,7 @@ from pypy.jit.metainterp.optimizeopt.optimizer import * from pypy.jit.metainterp.optimizeopt.generalize import KillHugeIntBounds from pypy.jit.metainterp.inliner import Inliner -from pypy.jit.metainterp.resoperation import rop, ResOperation +from pypy.jit.metainterp.resoperation import rop from pypy.jit.metainterp.resume import Snapshot import sys, os diff --git a/pypy/jit/metainterp/optimizeopt/virtualize.py b/pypy/jit/metainterp/optimizeopt/virtualize.py --- a/pypy/jit/metainterp/optimizeopt/virtualize.py +++ b/pypy/jit/metainterp/optimizeopt/virtualize.py @@ -4,7 +4,7 @@ from pypy.jit.metainterp.optimizeopt import optimizer from pypy.jit.metainterp.optimizeopt.util import (make_dispatcher_method, descrlist_dict, sort_descrs) -from pypy.jit.metainterp.resoperation import rop, ResOperation +from pypy.jit.metainterp.resoperation import rop from pypy.rlib.objectmodel import we_are_translated from pypy.jit.metainterp.optimizeopt.optimizer import OptValue diff --git a/pypy/jit/metainterp/optimizeopt/virtualstate.py b/pypy/jit/metainterp/optimizeopt/virtualstate.py --- a/pypy/jit/metainterp/optimizeopt/virtualstate.py +++ b/pypy/jit/metainterp/optimizeopt/virtualstate.py @@ -8,7 +8,7 @@ from pypy.jit.metainterp.history import BoxInt, ConstInt, BoxPtr, Const from pypy.jit.metainterp.optimize import InvalidLoop from pypy.jit.metainterp.optimizeopt.intutils import IntBound, IntUnbounded -from pypy.jit.metainterp.resoperation import rop, ResOperation +from pypy.jit.metainterp.resoperation import rop from pypy.rlib.objectmodel import we_are_translated from pypy.rlib.debug import debug_start, debug_stop, debug_print from pypy.rlib.objectmodel import we_are_translated diff --git a/pypy/jit/metainterp/optimizeopt/vstring.py b/pypy/jit/metainterp/optimizeopt/vstring.py --- a/pypy/jit/metainterp/optimizeopt/vstring.py +++ b/pypy/jit/metainterp/optimizeopt/vstring.py @@ -5,7 +5,7 @@ from pypy.jit.metainterp.optimizeopt.optimizer import CONST_0, CONST_1 from pypy.jit.metainterp.optimizeopt.optimizer import llhelper, REMOVED from pypy.jit.metainterp.optimizeopt.util import make_dispatcher_method -from pypy.jit.metainterp.resoperation import rop, ResOperation +from pypy.jit.metainterp.resoperation import rop from pypy.rlib.objectmodel import specialize, we_are_translated from pypy.rlib.unroll import unrolling_iterable from pypy.rpython import annlowlevel diff --git a/pypy/jit/metainterp/pyjitpl.py b/pypy/jit/metainterp/pyjitpl.py --- a/pypy/jit/metainterp/pyjitpl.py +++ b/pypy/jit/metainterp/pyjitpl.py @@ -9,7 +9,8 @@ from pypy.jit.metainterp import history, compile, resume from pypy.jit.metainterp.history import Const, ConstInt, ConstPtr, ConstFloat from pypy.jit.metainterp.history import Box, TargetToken -from pypy.jit.metainterp.resoperation import rop +from pypy.jit.metainterp.resoperation import rop, create_resop +from pypy.jit.metainterp import resoperation from pypy.jit.metainterp import executor from pypy.jit.metainterp.logger import Logger from pypy.jit.metainterp.jitprof import EmptyProfiler @@ -164,8 +165,10 @@ assert not oldbox.same_box(b) - def make_result_of_lastop(self, resultbox): - got_type = resultbox.type + def make_result_of_lastop(self, resultop): + got_type = resultop.type + if got_type == resoperation.VOID: + return # XXX disabled for now, conflicts with str_guard_value #if not we_are_translated(): # typeof = {'i': history.INT, @@ -173,14 +176,14 @@ # 'f': history.FLOAT} # assert typeof[self.jitcode._resulttypes[self.pc]] == got_type target_index = ord(self.bytecode[self.pc-1]) - if got_type == history.INT: - self.registers_i[target_index] = resultbox - elif got_type == history.REF: + if got_type == resoperation.INT: + self.registers_i[target_index] = resultop + elif got_type == resoperation.REF: #debug_print(' ->', # llmemory.cast_ptr_to_adr(resultbox.getref_base())) - self.registers_r[target_index] = resultbox - elif got_type == history.FLOAT: - self.registers_f[target_index] = resultbox + self.registers_r[target_index] = resultop + elif got_type == resoperation.FLOAT: + self.registers_f[target_index] = resultop else: raise AssertionError("bad result box type") @@ -1299,6 +1302,7 @@ @specialize.arg(1) def execute_varargs(self, opnum, argboxes, descr, exc, pure): + xxx self.metainterp.clear_exception() resbox = self.metainterp.execute_and_record_varargs(opnum, argboxes, descr=descr) @@ -1468,10 +1472,10 @@ # store this information for fastpath of call_assembler # (only the paths that can actually be taken) for jd in self.jitdrivers_sd: - name = {history.INT: 'int', - history.REF: 'ref', - history.FLOAT: 'float', - history.VOID: 'void'}[jd.result_type] + name = {resoperation.INT: 'int', + resoperation.REF: 'ref', + resoperation.FLOAT: 'float', + resoperation.VOID: 'void'}[jd.result_type] tokens = getattr(self, 'loop_tokens_done_with_this_frame_%s' % name) jd.portal_finishtoken = tokens[0].finishdescr num = self.cpu.get_fail_descr_number(tokens[0].finishdescr) @@ -1651,14 +1655,14 @@ self.aborted_tracing(stb.reason) sd = self.staticdata result_type = self.jitdriver_sd.result_type - if result_type == history.VOID: + if result_type == resoperation.VOID: assert resultbox is None raise sd.DoneWithThisFrameVoid() - elif result_type == history.INT: + elif result_type == resoperation.INT: raise sd.DoneWithThisFrameInt(resultbox.getint()) - elif result_type == history.REF: + elif result_type == resoperation.REF: raise sd.DoneWithThisFrameRef(self.cpu, resultbox.getref_base()) - elif result_type == history.FLOAT: + elif result_type == resoperation.FLOAT: raise sd.DoneWithThisFrameFloat(resultbox.getfloatstorage()) else: assert False @@ -1727,12 +1731,10 @@ # execute the operation profiler = self.staticdata.profiler profiler.count_ops(opnum) - resbox = executor.execute(self.cpu, self, opnum, descr, *argboxes) - if rop._ALWAYS_PURE_FIRST <= opnum <= rop._ALWAYS_PURE_LAST: - return self._record_helper_pure(opnum, resbox, descr, *argboxes) - else: - return self._record_helper_nonpure_varargs(opnum, resbox, descr, - list(argboxes)) + resop = executor.execute(self.cpu, self, opnum, descr, *argboxes) + if not resop.is_constant(): + self._record(resop) + return resop @specialize.arg(1) def execute_and_record_varargs(self, opnum, argboxes, descr=None): @@ -1751,15 +1753,6 @@ resbox = self._record_helper_nonpure_varargs(opnum, resbox, descr, argboxes) return resbox - def _record_helper_pure(self, opnum, resbox, descr, *argboxes): - canfold = self._all_constants(*argboxes) - if canfold: - resbox = resbox.constbox() # ensure it is a Const - return resbox - else: - resbox = resbox.nonconstbox() # ensure it is a Box - return self._record_helper_nonpure_varargs(opnum, resbox, descr, list(argboxes)) - def _record_helper_pure_varargs(self, opnum, resbox, descr, argboxes): canfold = self._all_constants_varargs(argboxes) if canfold: @@ -1783,6 +1776,18 @@ self.attach_debug_info(op) return resbox + def _record(self, resop): + opnum = resop.getopnum() + if (rop._OVF_FIRST <= opnum <= rop._OVF_LAST and + self.last_exc_value_box is None and + resop.all_constant_args()): + return resop.constbox() + profiler = self.staticdata.profiler + profiler.count_ops(opnum, Counters.RECORDED_OPS) + self.heapcache.invalidate_caches(resop) + self.history.record(resop) + self.attach_debug_info(resop) + return resop def attach_debug_info(self, op): if (not we_are_translated() and op is not None @@ -2157,17 +2162,17 @@ # temporarily put a JUMP to a pseudo-loop sd = self.staticdata result_type = self.jitdriver_sd.result_type - if result_type == history.VOID: + if result_type == resoperation.VOID: assert exitbox is None exits = [] loop_tokens = sd.loop_tokens_done_with_this_frame_void - elif result_type == history.INT: + elif result_type == resoperation.INT: exits = [exitbox] loop_tokens = sd.loop_tokens_done_with_this_frame_int - elif result_type == history.REF: + elif result_type == resoperation.REF: exits = [exitbox] loop_tokens = sd.loop_tokens_done_with_this_frame_ref - elif result_type == history.FLOAT: + elif result_type == resoperation.FLOAT: exits = [exitbox] loop_tokens = sd.loop_tokens_done_with_this_frame_float else: @@ -2175,7 +2180,7 @@ # FIXME: kill TerminatingLoopToken? # FIXME: can we call compile_trace? token = loop_tokens[0].finishdescr - self.history.record(rop.FINISH, exits, None, descr=token) + self.history.record(create_resop(rop.FINISH, exits, None, descr=token)) target_token = compile.compile_trace(self, self.resumekey) if target_token is not token: compile.giveup() @@ -2635,30 +2640,23 @@ if self.debug: print '\tpyjitpl: %s(%s)' % (name, ', '.join(map(repr, args))), try: - resultbox = unboundmethod(self, *args) + resultop = unboundmethod(self, *args) except Exception, e: if self.debug: print '-> %s!' % e.__class__.__name__ raise - if num_return_args == 0: - if self.debug: - print - assert resultbox is None - else: - if self.debug: - print '-> %r' % (resultbox,) - assert argcodes[next_argcode] == '>' - result_argcode = argcodes[next_argcode + 1] - assert resultbox.type == {'i': history.INT, - 'r': history.REF, - 'f': history.FLOAT}[result_argcode] + if self.debug: + print resultop + assert argcodes[next_argcode] == '>' + result_argcode = argcodes[next_argcode + 1] + assert resultop.type == {'i': resoperation.INT, + 'r': resoperation.REF, + 'f': resoperation.FLOAT, + 'v': resoperation.VOID}[result_argcode] else: - resultbox = unboundmethod(self, *args) + resultop = unboundmethod(self, *args) # - if resultbox is not None: - self.make_result_of_lastop(resultbox) - elif not we_are_translated(): - assert self._result_argcode in 'v?' + self.make_result_of_lastop(resultop) # unboundmethod = getattr(MIFrame, 'opimpl_' + name).im_func argtypes = unrolling_iterable(unboundmethod.argtypes) diff --git a/pypy/jit/metainterp/resoperation.py b/pypy/jit/metainterp/resoperation.py --- a/pypy/jit/metainterp/resoperation.py +++ b/pypy/jit/metainterp/resoperation.py @@ -4,9 +4,22 @@ from pypy.jit.codewriter import longlong from pypy.rlib.objectmodel import compute_identity_hash +INT = 'i' +REF = 'r' +FLOAT = 'f' +STRUCT = 's' +VOID = 'v' + @specialize.arg(0) -def ResOperation(opnum, args, result, descr=None): +def create_resop(opnum, args, result, descr=None): cls = opclasses[opnum] + assert cls.NUMARGS == -1 + if cls.is_always_pure(): + for arg in args: + if not arg.is_constant(): + break + else: + return cls.wrap_constant(result) if result is None: op = cls() else: @@ -17,6 +30,84 @@ op.setdescr(descr) return op +@specialize.arg(0) +def create_resop_0(opnum, result, descr=None): + cls = opclasses[opnum] + assert cls.NUMARGS == 0 + if result is None: + op = cls() + else: + op = cls(result) + if descr is not None: + assert isinstance(op, ResOpWithDescr) + op.setdescr(descr) + return op + +@specialize.arg(0) +def create_resop_1(opnum, arg0, result, descr=None): + cls = opclasses[opnum] + assert cls.NUMARGS == 1 + if cls.is_always_pure(): + if arg0.is_constant(): + return cls.wrap_constant(result) + if result is None: + op = cls() + else: + op = cls(result) + op._arg0 = arg0 + if descr is not None: + assert isinstance(op, ResOpWithDescr) + op.setdescr(descr) + return op + +@specialize.arg(0) +def create_resop_2(opnum, arg0, arg1, result, descr=None): + cls = opclasses[opnum] + assert cls.NUMARGS == 2 + if cls.is_always_pure(): + if arg0.is_constant() and arg1.is_constant(): + return cls.wrap_constant(result) + if result is None: + op = cls() + else: + op = cls(result) + op._arg0 = arg0 + op._arg1 = arg1 + if descr is not None: + assert isinstance(op, ResOpWithDescr) + op.setdescr(descr) + return op + +@specialize.arg(0) +def create_resop_3(opnum, arg0, arg1, arg2, result, descr=None): + cls = opclasses[opnum] + assert cls.NUMARGS == 3 + if cls.is_always_pure(): + if arg0.is_constant() and arg1.is_constant() and arg2.is_constant(): + return cls.wrap_constant(result) + if result is None: + op = cls() + else: + op = cls(result) + op._arg0 = arg0 + op._arg1 = arg1 + op._arg2 = arg2 + if descr is not None: + assert isinstance(op, ResOpWithDescr) + op.setdescr(descr) + return op + +def copy_and_change(self, opnum, args=None, result=None, descr=None): + "shallow copy: the returned operation is meant to be used in place of self" + if args is None: + args = self.getarglist() + if result is None: + result = self.result + if descr is None: + descr = self.getdescr() + newop = ResOperation(opnum, args, result, descr) + return newop + class AbstractValue(object): __slots__ = () @@ -72,6 +163,9 @@ def same_box(self, other): return self is other + def is_constant(self): + return False + class AbstractResOp(AbstractValue): """The central ResOperation class, representing one operation.""" @@ -80,8 +174,9 @@ pc = 0 opnum = 0 - def getopnum(self): - return self.opnum + @classmethod + def getopnum(cls): + return cls.opnum # methods implemented by the arity mixins # --------------------------------------- @@ -118,6 +213,9 @@ def getdescr(self): return None + def getdescrclone(self): + return None + def setdescr(self, descr): raise NotImplementedError @@ -127,28 +225,6 @@ # common methods # -------------- - def copy_and_change(self, opnum, args=None, result=None, descr=None): - "shallow copy: the returned operation is meant to be used in place of self" - if args is None: - args = self.getarglist() - if result is None: - result = self.result - if descr is None: - descr = self.getdescr() - newop = ResOperation(opnum, args, result, descr) - return newop - - def clone(self): - args = self.getarglist() - descr = self.getdescr() - if descr is not None: - descr = descr.clone_if_mutable() - op = ResOperation(self.getopnum(), args[:], self.result, descr) - if not we_are_translated(): - op.name = self.name - op.pc = self.pc - return op - def __repr__(self): try: return self.repr() @@ -176,56 +252,71 @@ return '%s%s%s(%s, descr=%r)' % (prefix, sres, self.getopname(), ', '.join([str(a) for a in args]), descr) - def getopname(self): + @classmethod + def getopname(cls): try: - return opname[self.getopnum()].lower() + return opname[cls.getopnum()].lower() except KeyError: - return '<%d>' % self.getopnum() + return '<%d>' % cls.getopnum() - def is_guard(self): - return rop._GUARD_FIRST <= self.getopnum() <= rop._GUARD_LAST + @classmethod + def is_guard(cls): + return rop._GUARD_FIRST <= cls.getopnum() <= rop._GUARD_LAST - def is_foldable_guard(self): - return rop._GUARD_FOLDABLE_FIRST <= self.getopnum() <= rop._GUARD_FOLDABLE_LAST + @classmethod + def is_foldable_guard(cls): + return rop._GUARD_FOLDABLE_FIRST <= cls.getopnum() <= rop._GUARD_FOLDABLE_LAST - def is_guard_exception(self): - return (self.getopnum() == rop.GUARD_EXCEPTION or - self.getopnum() == rop.GUARD_NO_EXCEPTION) + @classmethod + def is_guard_exception(cls): + return (cls.getopnum() == rop.GUARD_EXCEPTION or + cls.getopnum() == rop.GUARD_NO_EXCEPTION) - def is_guard_overflow(self): - return (self.getopnum() == rop.GUARD_OVERFLOW or - self.getopnum() == rop.GUARD_NO_OVERFLOW) + @classmethod + def is_guard_overflow(cls): + return (cls.getopnum() == rop.GUARD_OVERFLOW or + cls.getopnum() == rop.GUARD_NO_OVERFLOW) - def is_always_pure(self): - return rop._ALWAYS_PURE_FIRST <= self.getopnum() <= rop._ALWAYS_PURE_LAST + @classmethod + def is_always_pure(cls): + return rop._ALWAYS_PURE_FIRST <= cls.getopnum() <= rop._ALWAYS_PURE_LAST - def has_no_side_effect(self): - return rop._NOSIDEEFFECT_FIRST <= self.getopnum() <= rop._NOSIDEEFFECT_LAST + @classmethod + def has_no_side_effect(cls): + return rop._NOSIDEEFFECT_FIRST <= cls.getopnum() <= rop._NOSIDEEFFECT_LAST - def can_raise(self): - return rop._CANRAISE_FIRST <= self.getopnum() <= rop._CANRAISE_LAST + @classmethod + def can_raise(cls): + return rop._CANRAISE_FIRST <= cls.getopnum() <= rop._CANRAISE_LAST - def is_malloc(self): + @classmethod + def is_malloc(cls): # a slightly different meaning from can_malloc - return rop._MALLOC_FIRST <= self.getopnum() <= rop._MALLOC_LAST + return rop._MALLOC_FIRST <= cls.getopnum() <= rop._MALLOC_LAST - def can_malloc(self): - return self.is_call() or self.is_malloc() + @classmethod + def can_malloc(cls): + return cls.is_call() or cls.is_malloc() - def is_call(self): - return rop._CALL_FIRST <= self.getopnum() <= rop._CALL_LAST + @classmethod + def is_call(cls): + return rop._CALL_FIRST <= cls.getopnum() <= rop._CALL_LAST - def is_ovf(self): - return rop._OVF_FIRST <= self.getopnum() <= rop._OVF_LAST + @classmethod + def is_ovf(cls): + return rop._OVF_FIRST <= cls.getopnum() <= rop._OVF_LAST - def is_comparison(self): - return self.is_always_pure() and self.returns_bool_result() + @classmethod + def is_comparison(cls): + return cls.is_always_pure() and cls.returns_bool_result() - def is_final(self): - return rop._FINAL_FIRST <= self.getopnum() <= rop._FINAL_LAST + @classmethod + def is_final(cls): + return rop._FINAL_FIRST <= cls.getopnum() <= rop._FINAL_LAST - def returns_bool_result(self): - opnum = self.getopnum() + @classmethod + def returns_bool_result(cls): + opnum = cls.getopnum() if we_are_translated(): assert opnum >= 0 elif opnum < 0: @@ -234,12 +325,17 @@ class ResOpNone(object): _mixin_ = True + type = VOID def __init__(self): pass # no return value + def getresult(self): + return None + class ResOpInt(object): _mixin_ = True + type = INT def __init__(self, intval): assert isinstance(intval, int) @@ -247,9 +343,16 @@ def getint(self): return self.intval + getresult = getint + + @staticmethod + def wrap_constant(intval): + from pypy.jit.metainterp.history import ConstInt + return ConstInt(intval) class ResOpFloat(object): _mixin_ = True + type = FLOAT def __init__(self, floatval): #assert isinstance(floatval, float) @@ -258,9 +361,16 @@ def getfloatstorage(self): return self.floatval + getresult = getfloatstorage + + @staticmethod + def wrap_constant(floatval): + from pypy.jit.metainterp.history import ConstFloat + return ConstFloat(floatval) class ResOpPointer(object): _mixin_ = True + type = REF def __init__(self, pval): assert typeOf(pval) == GCREF @@ -268,6 +378,12 @@ def getref_base(self): return self.pval + getresult = getref_base + + @staticmethod + def wrap_constant(pval): + from pypy.jit.metainterp.history import ConstPtr + return ConstPtr(pval) # =================== # Top of the hierachy @@ -283,6 +399,9 @@ def getdescr(self): return self._descr + def getdescrclone(self): + return self._descr.clone_if_mutable() + def setdescr(self, descr): # for 'call', 'new', 'getfield_gc'...: the descr is a prebuilt # instance provided by the backend holding details about the type @@ -312,16 +431,6 @@ def setfailargs(self, fail_args): self._fail_args = fail_args - def copy_and_change(self, opnum, args=None, result=None, descr=None): - newop = AbstractResOp.copy_and_change(self, opnum, args, result, descr) - newop.setfailargs(self.getfailargs()) - return newop - - def clone(self): - newop = AbstractResOp.clone(self) - newop.setfailargs(self.getfailargs()) - return newop - # ============ # arity mixins # ============ @@ -329,6 +438,8 @@ class NullaryOp(object): _mixin_ = True + NUMARGS = 0 + def initarglist(self, args): assert len(args) == 0 @@ -344,11 +455,21 @@ def setarg(self, i, box): raise IndexError + def foreach_arg(self, func): + pass + + def clone(self): + r = create_resop_0(self.opnum, self.getresult(), self.getdescrclone()) + if self.is_guard(): + r.setfailargs(self.getfailargs()) + return r class UnaryOp(object): _mixin_ = True _arg0 = None + NUMARGS = 1 + def initarglist(self, args): assert len(args) == 1 self._arg0, = args @@ -371,12 +492,24 @@ else: raise IndexError + @specialize.arg(1) + def foreach_arg(self, func): + func(self.getopnum(), 0, self._arg0) + + def clone(self): + r = create_resop_1(self.opnum, self._arg0, self.getresult(), + self.getdescrclone()) + if self.is_guard(): + r.setfailargs(self.getfailargs()) + return r class BinaryOp(object): _mixin_ = True _arg0 = None _arg1 = None + NUMARGS = 2 + def initarglist(self, args): assert len(args) == 2 self._arg0, self._arg1 = args @@ -403,6 +536,18 @@ def getarglist(self): return [self._arg0, self._arg1] + @specialize.arg(1) + def foreach_arg(self, func): + func(self.getopnum(), 0, self._arg0) + func(self.getopnum(), 1, self._arg1) + + def clone(self): + r = create_resop_2(self.opnum, self._arg0, self._arg1, + self.getresult(), self.getdescrclone()) + if self.is_guard(): + r.setfailargs(self.getfailargs()) + return r + class TernaryOp(object): _mixin_ = True @@ -410,6 +555,8 @@ _arg1 = None _arg2 = None + NUMARGS = 3 + def initarglist(self, args): assert len(args) == 3 self._arg0, self._arg1, self._arg2 = args @@ -440,10 +587,24 @@ else: raise IndexError + @specialize.arg(1) + def foreach_arg(self, func): + func(self.getopnum(), 0, self._arg0) + func(self.getopnum(), 1, self._arg1) + func(self.getopnum(), 2, self._arg2) + + def clone(self): + assert not self.is_guard() + return create_resop_3(self.opnum, self._arg0, self._arg1, self._arg2, + self.getresult(), self.getdescrclone()) + + class N_aryOp(object): _mixin_ = True _args = None + NUMARGS = -1 + def initarglist(self, args): self._args = args @@ -459,6 +620,16 @@ def setarg(self, i, box): self._args[i] = box + @specialize.arg(1) + def foreach_arg(self, func): + for i, arg in enumerate(self._args): + func(self.getopnum(), i, arg) + + def clone(self): + assert not self.is_guard() + return create_resop(self.opnum, self._args[:], self.getresult(), + self.getdescrclone()) + # ____________________________________________________________ diff --git a/pypy/jit/metainterp/resume.py b/pypy/jit/metainterp/resume.py --- a/pypy/jit/metainterp/resume.py +++ b/pypy/jit/metainterp/resume.py @@ -1,7 +1,7 @@ import sys, os from pypy.jit.metainterp.history import Box, Const, ConstInt, getkind from pypy.jit.metainterp.history import BoxInt, BoxPtr, BoxFloat -from pypy.jit.metainterp.history import INT, REF, FLOAT, HOLE +from pypy.jit.metainterp.resoperation import INT, REF, FLOAT from pypy.jit.metainterp.history import AbstractDescr from pypy.jit.metainterp.resoperation import rop from pypy.jit.metainterp import jitprof diff --git a/pypy/jit/metainterp/test/test_resoperation.py b/pypy/jit/metainterp/test/test_resoperation.py --- a/pypy/jit/metainterp/test/test_resoperation.py +++ b/pypy/jit/metainterp/test/test_resoperation.py @@ -2,6 +2,19 @@ from pypy.jit.metainterp import resoperation as rop from pypy.jit.metainterp.history import AbstractDescr +class FakeBox(object): + def __init__(self, v): + self.v = v + + def __eq__(self, other): + return self.v == other.v + + def __ne__(self, other): + return not self == other + + def is_constant(self): + return False + def test_arity_mixins(): cases = [ (0, rop.NullaryOp), @@ -55,19 +68,20 @@ def test_instantiate(): from pypy.rpython.lltypesystem import lltype, llmemory - op = rop.ResOperation(rop.rop.INT_ADD, ['a', 'b'], 15) - assert op.getarglist() == ['a', 'b'] + op = rop.create_resop_2(rop.rop.INT_ADD, FakeBox('a'), FakeBox('b'), 15) + assert op.getarglist() == [FakeBox('a'), FakeBox('b')] assert op.getint() == 15 mydescr = AbstractDescr() - op = rop.ResOperation(rop.rop.CALL_f, ['a', 'b'], 15.5, descr=mydescr) - assert op.getarglist() == ['a', 'b'] + op = rop.create_resop(rop.rop.CALL_f, [FakeBox('a'), + FakeBox('b')], 15.5, descr=mydescr) + assert op.getarglist() == [FakeBox('a'), FakeBox('b')] assert op.getfloat() == 15.5 assert op.getdescr() is mydescr - op = rop.ResOperation(rop.rop.CALL_p, ['a', 'b'], + op = rop.create_resop(rop.rop.CALL_p, [FakeBox('a'), FakeBox('b')], lltype.nullptr(llmemory.GCREF.TO), descr=mydescr) - assert op.getarglist() == ['a', 'b'] + assert op.getarglist() == [FakeBox('a'), FakeBox('b')] assert not op.getref_base() assert op.getdescr() is mydescr @@ -76,15 +90,51 @@ mydescr = AbstractDescr() p = lltype.malloc(llmemory.GCREF.TO) - assert rop.ResOperation(rop.rop.NEW, [], p).can_malloc() - call = rop.ResOperation(rop.rop.CALL_i, ['a', 'b'], 3, descr=mydescr) + assert rop.create_resop_0(rop.rop.NEW, p).can_malloc() + call = rop.create_resop(rop.rop.CALL_i, [FakeBox('a'), + FakeBox('b')], 3, descr=mydescr) assert call.can_malloc() - assert not rop.ResOperation(rop.rop.INT_ADD, ['a', 'b'], 3).can_malloc() + assert not rop.create_resop_2(rop.rop.INT_ADD, FakeBox('a'), + FakeBox('b'), 3).can_malloc() def test_get_deep_immutable_oplist(): - ops = [rop.ResOperation(rop.rop.INT_ADD, ['a', 'b'], 3)] + ops = [rop.create_resop_2(rop.rop.INT_ADD, FakeBox('a'), FakeBox('b'), 3)] newops = rop.get_deep_immutable_oplist(ops) py.test.raises(TypeError, "newops.append('foobar')") py.test.raises(TypeError, "newops[0] = 'foobar'") py.test.raises(AssertionError, "newops[0].setarg(0, 'd')") py.test.raises(AssertionError, "newops[0].setdescr('foobar')") + +def test_clone(): + mydescr = AbstractDescr() + op = rop.create_resop_0(rop.rop.GUARD_NO_EXCEPTION, None, descr=mydescr) + op.setfailargs([3]) + op2 = op.clone() + assert not op2 is op + assert op2.getresult() is None + assert op2.getfailargs() is op.getfailargs() + op = rop.create_resop_1(rop.rop.INT_IS_ZERO, FakeBox('a'), 1) + op2 = op.clone() + assert op2 is not op + assert op2._arg0 == FakeBox('a') + assert op2.getint() == 1 + op = rop.create_resop_2(rop.rop.INT_ADD, FakeBox('a'), FakeBox('b'), 1) + op2 = op.clone() + assert op2 is not op + assert op2._arg0 == FakeBox('a') + assert op2._arg1 == FakeBox('b') + assert op2.getint() == 1 + op = rop.create_resop_3(rop.rop.STRSETITEM, FakeBox('a'), FakeBox('b'), + FakeBox('c'), None) + op2 = op.clone() + assert op2 is not op + assert op2._arg0 == FakeBox('a') + assert op2._arg1 == FakeBox('b') + assert op2._arg2 == FakeBox('c') + assert op2.getresult() is None + op = rop.create_resop(rop.rop.CALL_i, [FakeBox('a'), FakeBox('b'), + FakeBox('c')], 13, descr=mydescr) + op2 = op.clone() + assert op2 is not op + assert op2._args == [FakeBox('a'), FakeBox('b'), FakeBox('c')] + assert op2.getint() == 13 _______________________________________________ pypy-commit mailing list pypy-commit@python.org http://mail.python.org/mailman/listinfo/pypy-commit