[pypy-svn] r32556 - in pypy/dist/pypy: jit/codegen/i386/test jit/hintannotator jit/timeshifter jit/timeshifter/test rpython translator translator/backendopt translator/backendopt/test
ac at codespeak.net
ac at codespeak.net
Thu Sep 21 11:30:28 CEST 2006
Author: ac
Date: Thu Sep 21 11:30:27 2006
New Revision: 32556
Added:
pypy/dist/pypy/jit/timeshifter/transform.py
- copied unchanged from r32555, pypy/branch/timeshift-refactoring/pypy/jit/timeshifter/transform.py
Removed:
pypy/dist/pypy/jit/timeshifter/timeshift.py
Modified:
pypy/dist/pypy/jit/codegen/i386/test/test_genc_ts.py
pypy/dist/pypy/jit/hintannotator/annotator.py
pypy/dist/pypy/jit/hintannotator/bookkeeper.py
pypy/dist/pypy/jit/hintannotator/model.py
pypy/dist/pypy/jit/timeshifter/oop.py
pypy/dist/pypy/jit/timeshifter/rtimeshift.py
pypy/dist/pypy/jit/timeshifter/rtyper.py
pypy/dist/pypy/jit/timeshifter/rvalue.py
pypy/dist/pypy/jit/timeshifter/test/test_timeshift.py
pypy/dist/pypy/jit/timeshifter/vlist.py
pypy/dist/pypy/rpython/rtyper.py
pypy/dist/pypy/translator/backendopt/ssa.py
pypy/dist/pypy/translator/backendopt/test/test_ssa.py
pypy/dist/pypy/translator/simplify.py
Log:
(arigo, arre) Merging from branch:
svn merge -r 32480:32555 svn+ssh://codespeak.net/svn/pypy/branch/timeshift-refactoring .
Refactoring timeshifting into a graph shape transform and a rtyping phase.
Added a SSA_to_SSI helper to make graph transforming easier. (rev. 32501)
Added support for yellow calls, i.e. calling a function with some red arguments
but getting a green return.
Modified: pypy/dist/pypy/jit/codegen/i386/test/test_genc_ts.py
==============================================================================
--- pypy/dist/pypy/jit/codegen/i386/test/test_genc_ts.py (original)
+++ pypy/dist/pypy/jit/codegen/i386/test/test_genc_ts.py Thu Sep 21 11:30:27 2006
@@ -15,7 +15,7 @@
SEPLINE = 'running residual graph...\n'
def annotate_interface_functions(self):
- annhelper = self.htshift.annhelper
+ annhelper = self.hrtyper.annhelper
RGenOp = self.RGenOp
SEPLINE = self.SEPLINE
ml_generate_code = self.ml_generate_code
Modified: pypy/dist/pypy/jit/hintannotator/annotator.py
==============================================================================
--- pypy/dist/pypy/jit/hintannotator/annotator.py (original)
+++ pypy/dist/pypy/jit/hintannotator/annotator.py Thu Sep 21 11:30:27 2006
@@ -20,9 +20,6 @@
flowgraph = desc.specialize(input_args_hs)
return self.build_graph_types(flowgraph, input_args_hs)
- def simplify(self):
- pass
-
def consider_op_malloc(self, hs_TYPE):
TYPE = hs_TYPE.const
if getattr(self.policy, 'novirtualcontainer', False):
Modified: pypy/dist/pypy/jit/hintannotator/bookkeeper.py
==============================================================================
--- pypy/dist/pypy/jit/hintannotator/bookkeeper.py (original)
+++ pypy/dist/pypy/jit/hintannotator/bookkeeper.py Thu Sep 21 11:30:27 2006
@@ -65,6 +65,7 @@
self.descs = {}
self.tsgraph_maximal_call_families = UnionFind(TsGraphCallFamily)
self.annotator = hannotator
+ self.tsgraphsigs = {}
# circular imports hack
global hintmodel
from pypy.jit.hintannotator import model as hintmodel
@@ -109,7 +110,18 @@
return origin
def compute_at_fixpoint(self):
- pass
+ # compute and cache the green-ness of OriginFlags objects
+ # while we can do so (i.e. before the graphs are modified)
+ for origin in self.originflags.values():
+ if origin.spaceop is not None:
+ origin.greenargs_cached = origin.greenargs()
+ # compute and cache the signature of the graphs before they are
+ # modified by further code
+ ha = self.annotator
+ for tsgraph in ha.translator.graphs:
+ sig_hs = ([ha.binding(v) for v in tsgraph.getargs()],
+ ha.binding(tsgraph.getreturnvar()))
+ self.tsgraphsigs[tsgraph] = sig_hs
def immutableconstant(self, const):
res = hintmodel.SomeLLAbstractConstant(const.concretetype, {})
Modified: pypy/dist/pypy/jit/hintannotator/model.py
==============================================================================
--- pypy/dist/pypy/jit/hintannotator/model.py (original)
+++ pypy/dist/pypy/jit/hintannotator/model.py Thu Sep 21 11:30:27 2006
@@ -32,6 +32,8 @@
fixed = False
read_positions = None
+ greenargs_cached = None
+ is_call_result = False
def __init__(self, bookkeeper=None, spaceop=None):
self.bookkeeper = bookkeeper
@@ -61,8 +63,10 @@
def greenargs(self, frame=None):
annotator = self.bookkeeper.annotator
if frame is None:
+ if self.greenargs_cached is not None:
+ return self.greenargs_cached
frame = GreenHandlerFrame(annotator)
- if self.spaceop.opname == 'direct_call': # ah haa
+ if self.is_call_result:
return frame.greencallresult(self.spaceop)
else:
for v in self.spaceop.args:
@@ -93,6 +97,8 @@
## import pdb; pdb.set_trace()
args_hs = [self.annotator.binding(v) for v in spaceop.args]
hs_result = self.annotator.binding(spaceop.result)
+ if not isinstance(hs_result, SomeLLAbstractConstant):
+ return False # was generalized, e.g. to SomeLLAbstractVariable
hs_f1 = args_hs.pop(0)
fnobj = hs_f1.const._obj
if (getattr(self.annotator.policy, 'oopspec', False) and
@@ -229,6 +235,12 @@
else:
return hs_v1
+def originalconcretetype(hs):
+ if isinstance(hs, annmodel.SomeImpossibleValue):
+ return lltype.Void
+ else:
+ return hs.concretetype
+
# ____________________________________________________________
# operations
@@ -334,6 +346,7 @@
if isinstance(hs_res, SomeLLAbstractConstant):
hs_res.myorigin = bookkeeper.myorigin()
+ hs_res.myorigin.is_call_result = True
# we need to make sure that hs_res does not become temporarily less
# general as a result of calling another specialized version of the
Modified: pypy/dist/pypy/jit/timeshifter/oop.py
==============================================================================
--- pypy/dist/pypy/jit/timeshifter/oop.py (original)
+++ pypy/dist/pypy/jit/timeshifter/oop.py Thu Sep 21 11:30:27 2006
@@ -2,6 +2,7 @@
from pypy.rpython.extregistry import ExtRegistryEntry
from pypy.jit.timeshifter.rcontainer import cachedtype
from pypy.jit.timeshifter import rvalue, rtimeshift
+from pypy.translator.c import exceptiontransform
class Index:
@@ -13,7 +14,6 @@
__metaclass__ = cachedtype
def __init__(self, hrtyper, fnobj):
- ts = hrtyper.timeshifter
ll_func = fnobj._callable
FUNCTYPE = lltype.typeOf(fnobj)
nb_args = len(FUNCTYPE.ARGS)
@@ -45,7 +45,7 @@
if FUNCTYPE.RESULT is lltype.Void:
self.errorbox = None
else:
- error_value = ts.error_value(FUNCTYPE.RESULT)
+ error_value = exceptiontransform.error_value(FUNCTYPE.RESULT)
self.errorbox = rvalue.redbox_from_prebuilt_value(RGenOp,
error_value)
self.redboxbuilder = rvalue.ll_redboxbuilder(FUNCTYPE.RESULT)
@@ -64,8 +64,9 @@
# exception handling
graph = fnobj.graph
- self.can_raise = ts.etrafo.raise_analyzer.analyze_direct_call(graph)
- self.fetch_global_excdata = ts.fetch_global_excdata
+ etrafo = hrtyper.etrafo
+ self.can_raise = etrafo.raise_analyzer.analyze_direct_call(graph)
+ self.fetch_global_excdata = hrtyper.fetch_global_excdata
def residual_call(self, jitstate, argboxes):
builder = jitstate.curbuilder
Modified: pypy/dist/pypy/jit/timeshifter/rtimeshift.py
==============================================================================
--- pypy/dist/pypy/jit/timeshifter/rtimeshift.py (original)
+++ pypy/dist/pypy/jit/timeshifter/rtimeshift.py Thu Sep 21 11:30:27 2006
@@ -1,6 +1,8 @@
import operator, weakref
from pypy.rpython.lltypesystem import lltype, lloperation, llmemory
+from pypy.jit.hintannotator.model import originalconcretetype
from pypy.jit.timeshifter import rvalue
+from pypy.rpython.unroll import unrolling_iterable
FOLDABLE_OPS = dict.fromkeys(lloperation.enum_foldable_ops())
@@ -44,8 +46,8 @@
def make_opdesc(hop):
hrtyper = hop.rtyper
op_key = (hrtyper.RGenOp, hop.spaceop.opname,
- tuple([hrtyper.originalconcretetype(s_arg) for s_arg in hop.args_s]),
- hrtyper.originalconcretetype(hop.s_result))
+ tuple([originalconcretetype(s_arg) for s_arg in hop.args_s]),
+ originalconcretetype(hop.s_result))
try:
return _opdesc_cache[op_key]
except KeyError:
@@ -193,8 +195,7 @@
states_dic[key] = frozen, newblock
start_new_block._annspecialcase_ = "specialize:arglltype(2)"
-def retrieve_jitstate_for_merge(states_dic, jitstate, key, redboxes):
- save_locals(jitstate, redboxes)
+def retrieve_jitstate_for_merge(states_dic, jitstate, key):
if key not in states_dic:
start_new_block(states_dic, jitstate, key)
return False # continue
@@ -228,38 +229,54 @@
jitstate.enter_block(incoming, memo)
enter_next_block(jitstate, incoming)
-def leave_block_split(jitstate, switchredbox, exitindex,
- redboxes_true, redboxes_false):
- if switchredbox.is_constant():
- return rvalue.ll_getvalue(switchredbox, lltype.Bool)
- else:
- exitgvar = switchredbox.getgenvar(jitstate.curbuilder)
- later_builder = jitstate.curbuilder.jump_if_false(exitgvar)
- save_locals(jitstate, redboxes_false)
- jitstate.split(later_builder, exitindex)
- save_locals(jitstate, redboxes_true)
- enter_block(jitstate)
- return True
-
-def dispatch_next(oldjitstate, return_cache):
- split_queue = oldjitstate.frame.split_queue
- if split_queue:
- jitstate = split_queue.pop()
+def split(jitstate, switchredbox, resumepoint, *greens_gv):
+ exitgvar = switchredbox.getgenvar(jitstate.curbuilder)
+ later_builder = jitstate.curbuilder.jump_if_false(exitgvar)
+ jitstate.split(later_builder, resumepoint, list(greens_gv))
+
+def collect_split(jitstate_chain, resumepoint, *greens_gv):
+ greens_gv = list(greens_gv)
+ pending = jitstate_chain
+ while True:
+ jitstate = pending
+ pending = pending.next
+ jitstate.greens.extend(greens_gv) # item 0 is the return value
+ jitstate.resumepoint = resumepoint
+ if pending is None:
+ break
+ dispatch_queue = jitstate_chain.frame.dispatch_queue
+ jitstate.next = dispatch_queue.split_chain
+ dispatch_queue.split_chain = jitstate_chain.next
+ # XXX obscurity++ above
+
+def dispatch_next(oldjitstate):
+ dispatch_queue = oldjitstate.frame.dispatch_queue
+ if dispatch_queue.split_chain is not None:
+ jitstate = dispatch_queue.split_chain
+ dispatch_queue.split_chain = jitstate.next
enter_block(jitstate)
return jitstate
else:
- return leave_graph(oldjitstate.frame.return_queue, return_cache)
+ oldjitstate.resumepoint = -1
+ return oldjitstate
-def getexitindex(jitstate):
- return jitstate.exitindex
+def getresumepoint(jitstate):
+ return jitstate.resumepoint
-def save_locals(jitstate, redboxes):
+def save_locals(jitstate, *redboxes):
+ redboxes = list(redboxes)
assert None not in redboxes
jitstate.frame.local_boxes = redboxes
+def save_greens(jitstate, *greens_gv):
+ jitstate.greens = list(greens_gv)
+
def getlocalbox(jitstate, i):
return jitstate.frame.local_boxes[i]
+def ll_getgreenbox(jitstate, i, T):
+ return jitstate.greens[i].revealconst(T)
+
def getreturnbox(jitstate):
return jitstate.returnbox
@@ -276,16 +293,35 @@
jitstate.exc_value_box = box
def save_return(jitstate):
- jitstate.frame.return_queue.append(jitstate)
+ # add 'jitstate' to the chain of return-jitstates
+ dispatch_queue = jitstate.frame.dispatch_queue
+ jitstate.next = dispatch_queue.return_chain
+ dispatch_queue.return_chain = jitstate
-def ll_gvar_from_redbox(jitstate, redbox):
- return redbox.getgenvar(jitstate.curbuilder)
+##def ll_gvar_from_redbox(jitstate, redbox):
+## return redbox.getgenvar(jitstate.curbuilder)
-def ll_gvar_from_constant(jitstate, ll_value):
- return jitstate.curbuilder.rgenop.genconst(ll_value)
+##def ll_gvar_from_constant(jitstate, ll_value):
+## return jitstate.curbuilder.rgenop.genconst(ll_value)
# ____________________________________________________________
+class BaseDispatchQueue(object):
+ def __init__(self):
+ self.split_chain = None
+ self.return_chain = None
+
+def build_dispatch_subclass(attrnames):
+ if len(attrnames) == 0:
+ return BaseDispatchQueue
+ attrnames = unrolling_iterable(attrnames)
+ class DispatchQueue(BaseDispatchQueue):
+ def __init__(self):
+ BaseDispatchQueue.__init__(self)
+ for name in attrnames:
+ setattr(self, name, {}) # the new dicts have various types!
+ return DispatchQueue
+
class FrozenVirtualFrame(object):
fz_backframe = None
@@ -335,10 +371,9 @@
class VirtualFrame(object):
- def __init__(self, backframe, split_queue, return_queue):
+ def __init__(self, backframe, dispatch_queue):
self.backframe = backframe
- self.split_queue = split_queue
- self.return_queue = return_queue
+ self.dispatch_queue = dispatch_queue
#self.local_boxes = ... set by callers
def enter_block(self, incoming, memo):
@@ -360,9 +395,7 @@
newbackframe = None
else:
newbackframe = self.backframe.copy(memo)
- result = VirtualFrame(newbackframe,
- self.split_queue,
- self.return_queue)
+ result = VirtualFrame(newbackframe, self.dispatch_queue)
result.local_boxes = [box.copy(memo) for box in self.local_boxes]
return result
@@ -376,23 +409,29 @@
class JITState(object):
returnbox = None
+ next = None # for linked lists
def __init__(self, builder, frame, exc_type_box, exc_value_box,
- exitindex=-1):
+ resumepoint=-1, newgreens=[]):
self.curbuilder = builder
self.frame = frame
self.exc_type_box = exc_type_box
self.exc_value_box = exc_value_box
- self.exitindex = exitindex
+ self.resumepoint = resumepoint
+ self.greens = newgreens
- def split(self, newbuilder, newexitindex):
+ def split(self, newbuilder, newresumepoint, newgreens):
memo = rvalue.copy_memo()
later_jitstate = JITState(newbuilder,
self.frame.copy(memo),
self.exc_type_box .copy(memo),
self.exc_value_box.copy(memo),
- newexitindex)
- self.frame.split_queue.append(later_jitstate)
+ newresumepoint,
+ newgreens)
+ # add the later_jitstate to the chain of pending-for-dispatch_next()
+ dispatch_queue = self.frame.dispatch_queue
+ later_jitstate.next = dispatch_queue.split_chain
+ dispatch_queue.split_chain = later_jitstate
def enter_block(self, incoming, memo):
self.frame.enter_block(incoming, memo)
@@ -412,21 +451,50 @@
self.exc_value_box = self.exc_value_box.replace(memo)
-def enter_graph(jitstate):
- jitstate.frame = VirtualFrame(jitstate.frame, [], [])
-
-def leave_graph(return_queue, return_cache):
- for jitstate in return_queue[:-1]:
- res = retrieve_jitstate_for_merge(return_cache, jitstate, (),
- # XXX strange next argument
- jitstate.frame.local_boxes)
+def enter_graph(jitstate, DispatchQueueClass):
+ jitstate.frame = VirtualFrame(jitstate.frame, DispatchQueueClass())
+enter_graph._annspecialcase_ = 'specialize:arg(1)'
+# XXX is that too many specializations? ^^^
+
+def merge_returning_jitstates(jitstate):
+ return_chain = jitstate.frame.dispatch_queue.return_chain
+ return_cache = {}
+ still_pending = None
+ while return_chain is not None:
+ jitstate = return_chain
+ return_chain = return_chain.next
+ res = retrieve_jitstate_for_merge(return_cache, jitstate, ())
+ if res is False: # not finished
+ jitstate.next = still_pending
+ still_pending = jitstate
+ assert still_pending is not None
+ most_general_jitstate = still_pending
+ still_pending = still_pending.next
+ while still_pending is not None:
+ jitstate = still_pending
+ still_pending = still_pending.next
+ res = retrieve_jitstate_for_merge(return_cache, jitstate, ())
assert res is True # finished
- frozen, block = return_cache[()]
- jitstate = return_queue[-1]
+ return most_general_jitstate
+
+def leave_graph_red(jitstate):
+ jitstate = merge_returning_jitstates(jitstate)
myframe = jitstate.frame
- if myframe.local_boxes: # else it's a green Void return
- jitstate.returnbox = myframe.local_boxes[0]
- # ^^^ fetched by a 'fetch_return' operation
+ jitstate.returnbox = myframe.local_boxes[0]
+ # ^^^ fetched by a 'fetch_return' operation
jitstate.frame = myframe.backframe
- jitstate.exitindex = -1
return jitstate
+
+def leave_graph_void(jitstate):
+ jitstate = merge_returning_jitstates(jitstate)
+ myframe = jitstate.frame
+ jitstate.frame = myframe.backframe
+ return jitstate
+
+def leave_graph_yellow(jitstate):
+ return_chain = jitstate.frame.dispatch_queue.return_chain
+ jitstate = return_chain
+ while jitstate is not None:
+ jitstate.frame = jitstate.frame.backframe
+ jitstate = jitstate.next
+ return return_chain # a jitstate, which is the head of the chain
Modified: pypy/dist/pypy/jit/timeshifter/rtyper.py
==============================================================================
--- pypy/dist/pypy/jit/timeshifter/rtyper.py (original)
+++ pypy/dist/pypy/jit/timeshifter/rtyper.py Thu Sep 21 11:30:27 2006
@@ -10,7 +10,10 @@
from pypy.rpython.lltypesystem import lltype, llmemory
from pypy.jit.hintannotator import model as hintmodel
from pypy.jit.hintannotator import container as hintcontainer
-from pypy.jit.timeshifter import rtimeshift, rvalue, rcontainer
+from pypy.jit.hintannotator.model import originalconcretetype
+from pypy.jit.timeshifter import rtimeshift, rvalue, rcontainer, oop
+from pypy.jit.timeshifter.transform import HintGraphTransformer
+from pypy.jit.codegen import model as cgmodel
class HintTypeSystem(LowLevelTypeSystem):
name = "hinttypesystem"
@@ -36,27 +39,156 @@
# ___________________________________________________________
-def originalconcretetype(hs):
- if isinstance(hs, annmodel.SomeImpossibleValue):
- return lltype.Void
- else:
- return hs.concretetype
-
class HintRTyper(RPythonTyper):
- def __init__(self, hannotator, timeshifter):
+ def __init__(self, hannotator, rtyper, RGenOp):
RPythonTyper.__init__(self, hannotator,
type_system=HintTypeSystem.instance)
+ self.rtyper = rtyper
+ self.RGenOp = RGenOp
self.green_reprs = PRECOMPUTED_GREEN_REPRS.copy()
self.red_reprs = {}
- self.color_cache = {}
- self.timeshifter = timeshifter
- self.RGenOp = timeshifter.RGenOp
+ #self.color_cache = {}
+
+ self.annhelper = annlowlevel.MixLevelHelperAnnotator(rtyper)
+ self.timeshift_mapping = {}
+ self.sigs = {}
+ self.dispatchsubclasses = {}
+
+ (self.s_CodeGenerator,
+ self.r_CodeGenerator) = self.s_r_instanceof(cgmodel.CodeGenerator)
+ (self.s_JITState,
+ self.r_JITState) = self.s_r_instanceof(rtimeshift.JITState)
+ (self.s_RedBox,
+ self.r_RedBox) = self.s_r_instanceof(rvalue.RedBox)
+ (self.s_OopSpecDesc,
+ self.r_OopSpecDesc) = self.s_r_instanceof(oop.OopSpecDesc)
+ (self.s_ConstOrVar,
+ self.r_ConstOrVar) = self.s_r_instanceof(cgmodel.GenVarOrConst)
+ (self.s_Block,
+ self.r_Block) = self.s_r_instanceof(cgmodel.CodeGenBlock)
+
+ self.etrafo = hannotator.exceptiontransformer
+ self.cexcdata = self.etrafo.cexcdata
+ self.exc_data_ptr = self.cexcdata.value
+ gv_excdata = RGenOp.constPrebuiltGlobal(self.exc_data_ptr)
+ LL_EXC_TYPE = rtyper.exceptiondata.lltype_of_exception_type
+ LL_EXC_VALUE = rtyper.exceptiondata.lltype_of_exception_value
+ null_exc_type_box = rvalue.redbox_from_prebuilt_value(RGenOp,
+ lltype.nullptr(LL_EXC_TYPE.TO))
+ null_exc_value_box = rvalue.redbox_from_prebuilt_value(RGenOp,
+ lltype.nullptr(LL_EXC_VALUE.TO))
+
+ p = self.etrafo.rpyexc_fetch_type_ptr.value
+ gv_rpyexc_fetch_type = RGenOp.constPrebuiltGlobal(p)
+ tok_fetch_type = RGenOp.sigToken(lltype.typeOf(p).TO)
+ kind_etype = RGenOp.kindToken(LL_EXC_TYPE)
+
+ p = self.etrafo.rpyexc_fetch_value_ptr.value
+ gv_rpyexc_fetch_value = RGenOp.constPrebuiltGlobal(p)
+ tok_fetch_value = RGenOp.sigToken(lltype.typeOf(p).TO)
+ kind_evalue = RGenOp.kindToken(LL_EXC_VALUE)
+
+ p = self.etrafo.rpyexc_clear_ptr.value
+ gv_rpyexc_clear = RGenOp.constPrebuiltGlobal(p)
+ tok_clear = RGenOp.sigToken(lltype.typeOf(p).TO)
+
+ p = self.etrafo.rpyexc_raise_ptr.value
+ gv_rpyexc_raise = RGenOp.constPrebuiltGlobal(p)
+ tok_raise = RGenOp.sigToken(lltype.typeOf(p).TO)
+
+ def fetch_global_excdata(jitstate):
+ builder = jitstate.curbuilder
+ gv_etype = builder.genop_call(tok_fetch_type,
+ gv_rpyexc_fetch_type, [])
+ gv_evalue = builder.genop_call(tok_fetch_value,
+ gv_rpyexc_fetch_value, [])
+ builder.genop_call(tok_clear, gv_rpyexc_clear, [])
+ etypebox = rvalue.PtrRedBox(kind_etype, gv_etype)
+ evaluebox = rvalue.PtrRedBox(kind_evalue, gv_evalue)
+ rtimeshift.setexctypebox (jitstate, etypebox)
+ rtimeshift.setexcvaluebox(jitstate, evaluebox)
+ self.fetch_global_excdata = fetch_global_excdata
+
+ def store_global_excdata(jitstate):
+ builder = jitstate.curbuilder
+ etypebox = jitstate.exc_type_box
+ if etypebox.is_constant():
+ ll_etype = rvalue.ll_getvalue(etypebox, llmemory.Address)
+ if not ll_etype:
+ return # we known there is no exception set
+ evaluebox = jitstate.exc_value_box
+ gv_etype = etypebox .getgenvar(builder)
+ gv_evalue = evaluebox.getgenvar(builder)
+ builder.genop_call(tok_raise,
+ gv_rpyexc_raise, [gv_etype, gv_evalue])
+ self.store_global_excdata = store_global_excdata
+
+ def ll_fresh_jitstate(builder):
+ return rtimeshift.JITState(builder, None,
+ null_exc_type_box,
+ null_exc_value_box)
+ self.ll_fresh_jitstate = ll_fresh_jitstate
+
+ def ll_finish_jitstate(jitstate, graphsigtoken):
+ returnbox = rtimeshift.getreturnbox(jitstate)
+ gv_ret = returnbox.getgenvar(jitstate.curbuilder)
+ store_global_excdata(jitstate)
+ jitstate.curbuilder.finish_and_return(graphsigtoken, gv_ret)
+ self.ll_finish_jitstate = ll_finish_jitstate
+
+ def specialize(self, view=False):
+ """
+ Driver for running the timeshifter.
+ """
+ graphs = self.annotator.translator.graphs
+ if view:
+ for graph in graphs:
+ self.transform_graph(graph)
+ self.annotator.translator.view() # in the middle
+ for graph in graphs:
+ self.timeshift_graph(graph)
- originalconcretetype = staticmethod(originalconcretetype)
+ else:
+ # do the whole transformation graph-by-graph if there is no
+ # need to view the intermediate result
+ for graph in graphs:
+ self.transform_graph(graph)
+ self.timeshift_graph(graph)
+
+ def transform_graph(self, graph):
+ # prepare the graphs by inserting all bookkeeping/dispatching logic
+ # as special operations
+ assert graph.startblock in self.annotator.annotated
+ transformer = HintGraphTransformer(self.annotator, graph)
+ transformer.transform()
+ flowmodel.checkgraph(graph) # for now
+
+ def timeshift_graph(self, graph):
+ # specialize all blocks of this graph
+ for block in graph.iterblocks():
+ self.annotator.annotated[block] = graph
+ self.specialize_block(block)
+ # "normalize" the graphs by putting an explicit v_jitstate variable
+ # everywhere
+ self.insert_v_jitstate_everywhere(graph)
+ # the graph is now timeshifted, so it is *itself* no longer
+ # exception-transformed...
+ del graph.exceptiontransformed
+
+ # ____________________________________________________________
+
+ def s_r_instanceof(self, cls, can_be_None=True):
+ # Return a SomeInstance / InstanceRepr pair correspnding to the specified class.
+ return self.annhelper.s_r_instanceof(cls, can_be_None=can_be_None)
+
+ def get_sig_hs(self, tsgraph):
+ # the signature annotations are cached on the HintBookkeeper because
+ # the graph is transformed already
+ return self.annotator.bookkeeper.tsgraphsigs[tsgraph]
def make_new_lloplist(self, block):
- return HintLowLevelOpList(self.timeshifter)
+ return HintLowLevelOpList(self)
def getgreenrepr(self, lowleveltype):
try:
@@ -75,20 +207,65 @@
if isinstance(lowleveltype, lltype.Ptr):
if isinstance(lowleveltype.TO, lltype.Struct):
redreprcls = RedStructRepr
- r = redreprcls(lowleveltype, self.timeshifter)
+ r = redreprcls(lowleveltype, self)
self.red_reprs[lowleveltype] = r
return r
- def gethscolor(self, hs):
+## def gethscolor(self, hs):
+## try:
+## return self.color_cache[id(hs)]
+## except KeyError:
+## if hs.is_green():
+## color = "green"
+## else:
+## color = "red"
+## self.color_cache[id(hs)] = color
+## return color
+
+ def get_dispatch_subclass(self, mergepointfamily):
try:
- return self.color_cache[id(hs)]
+ return self.dispatchsubclasses[mergepointfamily]
except KeyError:
- if hs.is_green():
- color = "green"
- else:
- color = "red"
- self.color_cache[id(hs)] = color
- return color
+ attrnames = mergepointfamily.getattrnames()
+ subclass = rtimeshift.build_dispatch_subclass(attrnames)
+ self.dispatchsubclasses[mergepointfamily] = subclass
+ return subclass
+
+ def get_timeshifted_fnptr(self, graph, specialization_key):
+ bk = self.annotator.bookkeeper
+ tsgraph = bk.get_graph_by_key(graph, specialization_key)
+ args_hs, hs_res = self.get_sig_hs(tsgraph)
+ args_r = [self.getrepr(hs_arg) for hs_arg in args_hs]
+ ARGS = [self.r_JITState.lowleveltype]
+ ARGS += [r.lowleveltype for r in args_r]
+ RESULT = self.r_JITState.lowleveltype
+ fnptr = lltype.functionptr(lltype.FuncType(ARGS, RESULT),
+ tsgraph.name,
+ graph=tsgraph,
+ _callable = graph.func)
+ return fnptr, args_r
+
+ def insert_v_jitstate_everywhere(self, graph):
+ from pypy.translator.unsimplify import varoftype
+ for block in graph.iterblocks():
+ v_jitstate = varoftype(self.r_JITState.lowleveltype, 'jitstate')
+ if block is graph.returnblock:
+ assert block.inputargs[0].concretetype is lltype.Void
+ del block.inputargs[0]
+ block.inputargs = [v_jitstate] + block.inputargs
+ for op in block.operations:
+ if op.opname == 'getjitstate':
+ op.opname = 'same_as'
+ op.args = [v_jitstate]
+ elif op.opname == 'setjitstate':
+ [v_jitstate] = op.args
+ for i in range(len(block.operations)-1, -1, -1):
+ if block.operations[i].opname == 'setjitstate':
+ del block.operations[i]
+ for link in block.exits:
+ if link.target is graph.returnblock:
+ del link.args[0] # Void
+ link.args = [v_jitstate] + link.args
def generic_translate_operation(self, hop, force=False):
# detect constant-foldable all-green operations
@@ -114,7 +291,7 @@
ll_generate = rtimeshift.ll_gen1
elif opdesc.nb_args == 2:
ll_generate = rtimeshift.ll_gen2
- ts = self.timeshifter
+ ts = self
c_opdesc = inputconst(lltype.Void, opdesc)
s_opdesc = ts.rtyper.annotator.bookkeeper.immutablevalue(opdesc)
v_jitstate = hop.llops.getjitstate()
@@ -133,7 +310,7 @@
T = originalconcretetype(hop.args_s[0])
v_redbox = hop.inputarg(self.getredrepr(T), arg=0)
assert isinstance(hop.r_result, GreenRepr)
- ts = self.timeshifter
+ ts = self
c_T = hop.inputconst(lltype.Void, T)
s_T = ts.rtyper.annotator.bookkeeper.immutablevalue(T)
s_res = annmodel.lltype_to_annotation(T)
@@ -157,7 +334,7 @@
def translate_op_getfield(self, hop):
if isinstance(hop.args_r[0], BlueRepr):
return hop.args_r[0].timeshift_getfield(hop)
- ts = self.timeshifter
+ ts = self
if hop.args_v[0] == ts.cexcdata:
# reading one of the exception boxes (exc_type or exc_value)
fieldname = hop.args_v[1].value
@@ -198,7 +375,7 @@
if res is not None:
return res
- ts = self.timeshifter
+ ts = self
v_argbox, v_index = hop.inputargs(self.getredrepr(PTRTYPE),
self.getredrepr(lltype.Signed))
fielddesc = rcontainer.ArrayFieldDesc(self.RGenOp, PTRTYPE.TO)
@@ -217,7 +394,7 @@
return res
PTRTYPE = originalconcretetype(hop.args_s[0])
- ts = self.timeshifter
+ ts = self
[v_argbox] = hop.inputargs(self.getredrepr(PTRTYPE))
fielddesc = rcontainer.ArrayFieldDesc(self.RGenOp, PTRTYPE.TO)
@@ -234,7 +411,7 @@
def translate_op_setfield(self, hop):
if isinstance(hop.args_r[0], BlueRepr):
return hop.args_r[0].timeshift_setfield(hop)
- ts = self.timeshifter
+ ts = self
PTRTYPE = originalconcretetype(hop.args_s[0])
VALUETYPE = originalconcretetype(hop.args_s[2])
if hop.args_v[0] == ts.cexcdata:
@@ -271,7 +448,7 @@
def translate_op_setarrayitem(self, hop):
PTRTYPE = originalconcretetype(hop.args_s[0])
VALUETYPE = PTRTYPE.TO.OF
- ts = self.timeshifter
+ ts = self
v_argbox, v_index, v_valuebox= hop.inputargs(self.getredrepr(PTRTYPE),
self.getredrepr(lltype.Signed),
self.getredrepr(VALUETYPE))
@@ -287,7 +464,7 @@
def translate_op_getsubstruct(self, hop):
##if isinstance(hop.args_r[0], BlueRepr):
## return hop.args_r[0].timeshift_getsubstruct(hop)
- ts = self.timeshifter
+ ts = self
PTRTYPE = originalconcretetype(hop.args_s[0])
v_argbox, c_fieldname = hop.inputargs(self.getredrepr(PTRTYPE),
green_void_repr)
@@ -311,7 +488,7 @@
return r_result.create(hop)
def translate_op_malloc_varsize(self, hop):
- ts = self.timeshifter
+ ts = self
assert isinstance(hop.r_result, RedRepr)
PTRTYPE = originalconcretetype(hop.s_result)
TYPE = PTRTYPE.TO
@@ -329,7 +506,7 @@
def translate_op_ptr_nonzero(self, hop, reverse=False):
- ts = self.timeshifter
+ ts = self
PTRTYPE = originalconcretetype(hop.args_s[0])
v_argbox, = hop.inputargs(self.getredrepr(PTRTYPE))
v_jitstate = hop.llops.getjitstate()
@@ -343,35 +520,10 @@
return self.translate_op_ptr_nonzero(hop, reverse=True)
- def guess_call_kind(self, spaceop):
- if spaceop.opname == 'indirect_call':
- return 'red' # for now
- assert spaceop.opname == 'direct_call'
- c_func = spaceop.args[0]
- fnobj = c_func.value._obj
- s_result = self.annotator.binding(spaceop.result)
- r_result = self.getrepr(s_result)
- if hasattr(fnobj._callable, 'oopspec'):
- return 'oopspec'
- elif (originalconcretetype(s_result) is not lltype.Void and
- isinstance(r_result, GreenRepr)):
- for v in spaceop.args:
- s_arg = self.annotator.binding(v)
- r_arg = self.getrepr(s_arg)
- if not isinstance(r_arg, GreenRepr):
- return 'yellow'
- return 'green'
- else:
- return 'red'
-
- def translate_op_direct_call(self, hop):
- kind = self.guess_call_kind(hop.spaceop)
- meth = getattr(self, 'handle_%s_call' % (kind,))
- return meth(hop)
-
def translate_op_indirect_call(self, hop):
+ XXX
bk = self.annotator.bookkeeper
- ts = self.timeshifter
+ ts = self
v_jitstate = hop.llops.getjitstate()
v_funcbox = hop.args_v[0]
graph_list = hop.args_v[-1].value
@@ -396,32 +548,221 @@
v_newjitstate = hop.genop('indirect_call', args_v, RESULT)
hop.llops.setjitstate(v_newjitstate)
+ # special operations inserted by the HintGraphTransformer
+
+ def translate_op_enter_graph(self, hop):
+ mpfamily = hop.args_v[0].value
+ subclass = self.get_dispatch_subclass(mpfamily)
+ s_subclass = self.rtyper.annotator.bookkeeper.immutablevalue(subclass)
+ c_subclass = inputconst(lltype.Void, subclass)
+ v_jitstate = hop.llops.getjitstate()
+ hop.llops.genmixlevelhelpercall(rtimeshift.enter_graph,
+ [self.s_JITState, s_subclass],
+ [v_jitstate , c_subclass],
+ annmodel.s_None)
+
+ def translate_op_leave_graph_red(self, hop):
+ v_jitstate = hop.llops.getjitstate()
+ v_newjs = hop.llops.genmixlevelhelpercall(rtimeshift.leave_graph_red,
+ [self.s_JITState],
+ [v_jitstate ],
+ self.s_JITState)
+ hop.llops.setjitstate(v_newjs)
+
+ def translate_op_leave_graph_void(self, hop):
+ v_jitstate = hop.llops.getjitstate()
+ v_newjs = hop.llops.genmixlevelhelpercall(rtimeshift.leave_graph_void,
+ [self.s_JITState],
+ [v_jitstate ],
+ self.s_JITState)
+ hop.llops.setjitstate(v_newjs)
+
+ def translate_op_leave_graph_yellow(self, hop):
+ v_jitstate = hop.llops.getjitstate()
+ v_njs = hop.llops.genmixlevelhelpercall(rtimeshift.leave_graph_yellow,
+ [self.s_JITState],
+ [v_jitstate ],
+ self.s_JITState)
+ hop.llops.setjitstate(v_njs)
def translate_op_save_locals(self, hop):
- ts = self.timeshifter
v_jitstate = hop.llops.getjitstate()
- v_boxes = ts.build_box_list(hop.llops, hop.args_v)
+ boxes_r = [self.getredrepr(originalconcretetype(hs))
+ for hs in hop.args_s]
+ boxes_v = hop.inputargs(*boxes_r)
+ boxes_s = [self.s_RedBox] * len(hop.args_v)
hop.llops.genmixlevelhelpercall(rtimeshift.save_locals,
- [ts.s_JITState, ts.s_box_list],
- [v_jitstate, v_boxes],
+ [self.s_JITState] + boxes_s,
+ [v_jitstate ] + boxes_v,
+ annmodel.s_None)
+
+ def translate_op_save_greens(self, hop):
+ v_jitstate = hop.llops.getjitstate()
+ greens_v = list(self.wrap_green_vars(hop.llops, hop.args_v))
+ greens_s = [self.s_ConstOrVar] * len(greens_v)
+ return hop.llops.genmixlevelhelpercall(rtimeshift.save_greens,
+ [self.s_JITState] + greens_s,
+ [v_jitstate ] + greens_v,
+ annmodel.s_None)
+
+ def translate_op_enter_block(self, hop):
+ v_jitstate = hop.llops.getjitstate()
+ hop.llops.genmixlevelhelpercall(rtimeshift.enter_block,
+ [self.s_JITState],
+ [v_jitstate ],
annmodel.s_None)
def translate_op_restore_local(self, hop):
- ts = self.timeshifter
assert isinstance(hop.args_v[0], flowmodel.Constant)
index = hop.args_v[0].value
+ c_index = hop.inputconst(lltype.Signed, index)
v_jitstate = hop.llops.getjitstate()
- return ts.read_out_box(hop.llops, v_jitstate, index)
+ return hop.llops.genmixlevelhelpercall(rtimeshift.getlocalbox,
+ [self.s_JITState, annmodel.SomeInteger(nonneg=True)],
+ [v_jitstate , c_index ],
+ self.s_RedBox)
+
+ def translate_op_restore_green(self, hop):
+ assert isinstance(hop.args_v[0], flowmodel.Constant)
+ index = hop.args_v[0].value
+ c_index = hop.inputconst(lltype.Signed, index)
+ TYPE = originalconcretetype(hop.s_result)
+ s_TYPE = self.rtyper.annotator.bookkeeper.immutablevalue(TYPE)
+ c_TYPE = hop.inputconst(lltype.Void, TYPE)
+ s_result = annmodel.lltype_to_annotation(TYPE)
+ v_jitstate = hop.llops.getjitstate()
+ return hop.llops.genmixlevelhelpercall(rtimeshift.ll_getgreenbox,
+ [self.s_JITState, annmodel.SomeInteger(nonneg=True), s_TYPE],
+ [v_jitstate , c_index , c_TYPE],
+ s_result)
def translate_op_fetch_return(self, hop):
- ts = self.timeshifter
+ ts = self
v_jitstate = hop.llops.getjitstate()
return hop.llops.genmixlevelhelpercall(rtimeshift.getreturnbox,
[ts.s_JITState],
[v_jitstate ],
ts.s_RedBox)
- def handle_oopspec_call(self, hop):
+ def translate_op_is_constant(self, hop):
+ hs = hop.args_s[0]
+ r_arg = self.getredrepr(originalconcretetype(hs))
+ [v_arg] = hop.inputargs(r_arg)
+ return hop.llops.genmixlevelhelpercall(rvalue.ll_is_constant,
+ [self.s_RedBox],
+ [v_arg ],
+ annmodel.SomeBool())
+
+ def translate_op_revealconst(self, hop):
+ hs = hop.args_s[0]
+ TYPE = originalconcretetype(hs)
+ r_arg = self.getredrepr(TYPE)
+ [v_arg] = hop.inputargs(r_arg)
+ s_TYPE = self.rtyper.annotator.bookkeeper.immutablevalue(TYPE)
+ c_TYPE = hop.inputconst(lltype.Void, TYPE)
+ s_result = annmodel.lltype_to_annotation(TYPE)
+ return hop.llops.genmixlevelhelpercall(rvalue.ll_getvalue,
+ [self.s_RedBox, s_TYPE],
+ [v_arg , c_TYPE],
+ s_result)
+
+ def wrap_green_vars(self, llops, vars):
+ v_jitstate = llops.getjitstate()
+ for var in vars:
+ s_var = annmodel.lltype_to_annotation(var.concretetype)
+ yield llops.genmixlevelhelpercall(rvalue.ll_gv_fromvalue,
+ [self.s_JITState, s_var],
+ [v_jitstate, var ],
+ self.s_ConstOrVar)
+
+ def translate_op_split(self, hop):
+ r_switch = self.getredrepr(lltype.Bool)
+ GREENS = [v.concretetype for v in hop.args_v[2:]]
+ greens_r = [self.getgreenrepr(TYPE) for TYPE in GREENS]
+ vlist = hop.inputargs(r_switch, lltype.Signed, *greens_r)
+
+ v_jitstate = hop.llops.getjitstate()
+ v_switch = vlist[0]
+ c_resumepoint = vlist[1]
+ greens_v = list(self.wrap_green_vars(hop.llops, vlist[2:]))
+
+ s_Int = annmodel.SomeInteger(nonneg=True)
+ args_s = [self.s_JITState, self.s_RedBox, s_Int]
+ args_s += [self.s_ConstOrVar] * len(greens_v)
+ args_v = [v_jitstate, v_switch, c_resumepoint]
+ args_v += greens_v
+ hop.llops.genmixlevelhelpercall(rtimeshift.split, args_s, args_v,
+ annmodel.s_None)
+
+ def translate_op_collect_split(self, hop):
+ GREENS = [v.concretetype for v in hop.args_v[1:]]
+ greens_r = [self.getgreenrepr(TYPE) for TYPE in GREENS]
+ vlist = hop.inputargs(lltype.Signed, *greens_r)
+
+ v_jitstate = hop.llops.getjitstate()
+ c_resumepoint = vlist[0]
+ greens_v = list(self.wrap_green_vars(hop.llops, vlist[1:]))
+
+ s_Int = annmodel.SomeInteger(nonneg=True)
+ args_s = [self.s_JITState, s_Int]
+ args_s += [self.s_ConstOrVar] * len(greens_v)
+ args_v = [v_jitstate, c_resumepoint]
+ args_v += greens_v
+ hop.llops.genmixlevelhelpercall(rtimeshift.collect_split,
+ args_s, args_v,
+ annmodel.s_None)
+
+ def translate_op_merge_point(self, hop):
+ mpfamily = hop.args_v[0].value
+ attrname = hop.args_v[1].value
+ DispatchQueueSubclass = self.get_dispatch_subclass(mpfamily)
+
+ def merge_point(jitstate, *key):
+ dispatch_queue = jitstate.frame.dispatch_queue
+ assert isinstance(dispatch_queue, DispatchQueueSubclass)
+ states_dic = getattr(dispatch_queue, attrname)
+ return rtimeshift.retrieve_jitstate_for_merge(states_dic,
+ jitstate, key)
+
+ greens_v = []
+ greens_s = []
+ for r, v in zip(hop.args_r[2:], hop.args_v[2:]):
+ s_precise_type = r.annotation()
+ s_erased_type = r.erased_annotation()
+ r_precise_type = self.rtyper.getrepr(s_precise_type)
+ r_erased_type = self.rtyper.getrepr(s_erased_type)
+ greens_v.append(hop.llops.convertvar(v, r_precise_type,
+ r_erased_type))
+ greens_s.append(s_erased_type)
+
+ v_jitstate = hop.llops.getjitstate()
+ return hop.llops.genmixlevelhelpercall(merge_point,
+ [self.s_JITState] + greens_s,
+ [v_jitstate ] + greens_v,
+ annmodel.SomeBool())
+
+ def translate_op_save_return(self, hop):
+ v_jitstate = hop.llops.getjitstate()
+ return hop.llops.genmixlevelhelpercall(rtimeshift.save_return,
+ [self.s_JITState],
+ [v_jitstate ],
+ annmodel.s_None)
+
+ def translate_op_dispatch_next(self, hop):
+ v_jitstate = hop.llops.getjitstate()
+ v_newjs = hop.llops.genmixlevelhelpercall(rtimeshift.dispatch_next,
+ [self.s_JITState],
+ [v_jitstate ],
+ self.s_JITState)
+ hop.llops.setjitstate(v_newjs)
+ return hop.llops.genmixlevelhelpercall(rtimeshift.getresumepoint,
+ [self.s_JITState],
+ [v_newjs ],
+ annmodel.SomeInteger())
+
+ # handling of the various kinds of calls
+
+ def translate_op_oopspec_call(self, hop):
# special-cased call, for things like list methods
from pypy.jit.timeshifter.oop import OopSpecDesc, Index
@@ -442,7 +783,7 @@
# if the ll_handler() takes more arguments, it must be 'None' defaults.
# Pass them as constant Nones.
- ts = self.timeshifter
+ ts = self
ll_handler = oopspecdesc.ll_handler
missing_args = ((ll_handler.func_code.co_argcount - 2) -
len(oopspecdesc.argtuple))
@@ -470,17 +811,15 @@
[v_jitstate, c_oopspecdesc] + args_v,
s_result)
- def handle_green_call(self, hop):
- # green-returning call, for now (XXX) we assume it's an
- # all-green function that we can just call
+ def translate_op_green_call(self, hop):
for r_arg in hop.args_r:
assert isinstance(r_arg, GreenRepr)
v = hop.genop('direct_call', hop.args_v, hop.r_result.lowleveltype)
return v
- def handle_red_call(self, hop):
+ def translate_op_red_call(self, hop):
bk = self.annotator.bookkeeper
- ts = self.timeshifter
+ ts = self
v_jitstate = hop.llops.getjitstate()
c_func = hop.args_v[0]
fnobj = c_func.value._obj
@@ -496,14 +835,16 @@
v_newjitstate = hop.genop('direct_call', args_v, RESULT)
hop.llops.setjitstate(v_newjitstate)
+ translate_op_yellow_call = translate_op_red_call
+
class HintLowLevelOpList(LowLevelOpList):
"""Warning: the HintLowLevelOpList's rtyper is the *original*
rtyper, while the HighLevelOp's rtyper is actually our HintRTyper...
"""
- def __init__(self, timeshifter):
- LowLevelOpList.__init__(self, timeshifter.rtyper)
- self.timeshifter = timeshifter
+ def __init__(self, hrtyper):
+ LowLevelOpList.__init__(self, hrtyper.rtyper)
+ self.hrtyper = hrtyper
def hasparentgraph(self):
return False # for now
@@ -524,23 +865,22 @@
args_v = [v_self] + args_v
function = function.im_func
- graph = self.timeshifter.annhelper.getgraph(function, args_s, s_result)
+ graph = self.hrtyper.annhelper.getgraph(function, args_s, s_result)
self.record_extra_call(graph) # xxx
- c = self.timeshifter.annhelper.graph2const(graph)
+ c = self.hrtyper.annhelper.graph2const(graph)
# build the 'direct_call' operation
- rtyper = self.timeshifter.rtyper
try:
RESULT = annmodel.annotation_to_lltype(s_result)
except ValueError:
- RESULT = rtyper.getrepr(s_result).lowleveltype
+ RESULT = self.rtyper.getrepr(s_result).lowleveltype
return self.genop('direct_call', [c]+args_v,
resulttype = RESULT)
def getjitstate(self):
return self.genop('getjitstate', [],
- resulttype = self.timeshifter.r_JITState)
+ resulttype = self.hrtyper.r_JITState)
def setjitstate(self, v_newjitstate):
self.genop('setjitstate', [v_newjitstate])
@@ -550,14 +890,14 @@
class __extend__(pairtype(HintTypeSystem, hintmodel.SomeLLAbstractValue)):
def rtyper_makerepr((ts, hs_c), hrtyper):
- if hrtyper.gethscolor(hs_c) == 'green':
+ if hs_c.is_green():
return hrtyper.getgreenrepr(hs_c.concretetype)
else:
return hrtyper.getredrepr(hs_c.concretetype)
def rtyper_makekey((ts, hs_c), hrtyper):
- color = hrtyper.gethscolor(hs_c)
- return hs_c.__class__, color, hs_c.concretetype
+ is_green = hs_c.is_green()
+ return hs_c.__class__, is_green, hs_c.concretetype
class __extend__(pairtype(HintTypeSystem, hintmodel.SomeLLAbstractContainer)):
@@ -568,7 +908,7 @@
# fall back to a red repr
return hrtyper.getredrepr(hs_container.concretetype)
return BlueStructRepr(hs_container.concretetype, vstructdef,
- hrtyper.timeshifter)
+ hrtyper)
def rtyper_makekey((ts, hs_container), hrtyper):
vstructdef = hs_container.contentdef
@@ -597,26 +937,26 @@
return hs_c.__class__,
class RedRepr(Repr):
- def __init__(self, original_concretetype, timeshifter):
+ def __init__(self, original_concretetype, hrtyper):
assert original_concretetype is not lltype.Void, (
"cannot make red boxes for the lltype Void")
self.original_concretetype = original_concretetype
- self.lowleveltype = timeshifter.r_RedBox.lowleveltype
- self.timeshifter = timeshifter
+ self.lowleveltype = hrtyper.r_RedBox.lowleveltype
+ self.hrtyper = hrtyper
- def get_genop_var(self, v, llops):
- ts = self.timeshifter
- v_jitstate = hop.llops.getjitstate()
- return llops.genmixlevelhelpercall(rtimeshift.ll_gvar_from_redbox,
- [ts.s_JITState, llops.timeshifter.s_RedBox],
- [v_jitstate, v],
- ts.s_ConstOrVar)
+## def get_genop_var(self, v, llops):
+## ts = self.hrtyper
+## v_jitstate = hop.llops.getjitstate()
+## return llops.genmixlevelhelpercall(rtimeshift.ll_gvar_from_redbox,
+## [ts.s_JITState, llops.hrtyper.s_RedBox],
+## [v_jitstate, v],
+## ts.s_ConstOrVar)
def convert_const(self, ll_value):
- RGenOp = self.timeshifter.RGenOp
+ RGenOp = self.hrtyper.RGenOp
redbox = rvalue.redbox_from_prebuilt_value(RGenOp, ll_value)
- timeshifter = self.timeshifter
- return timeshifter.annhelper.delayedconst(timeshifter.r_RedBox, redbox)
+ hrtyper = self.hrtyper
+ return hrtyper.annhelper.delayedconst(hrtyper.r_RedBox, redbox)
def residual_values(self, ll_value):
return [ll_value]
@@ -626,7 +966,7 @@
typedesc = None
def create(self, hop):
- ts = self.timeshifter
+ ts = self.hrtyper
if self.typedesc is None:
T = self.original_concretetype.TO
self.typedesc = rcontainer.StructTypeDesc(ts.RGenOp, T)
@@ -658,13 +998,13 @@
else:
return annmodel.SomeInteger()
- def get_genop_var(self, v, llops):
- ts = self.timeshifter
- v_jitstate = hop.llops.getjitstate()
- return llops.genmixlevelhelpercall(rtimeshift.ll_gvar_from_constant,
- [ts.s_JITState, self.annotation()],
- [v_jitstate, v],
- ts.s_ConstOrVar)
+## def get_genop_var(self, v, llops):
+## ts = self.hrtyper
+## v_jitstate = hop.llops.getjitstate()
+## return llops.genmixlevelhelpercall(rtimeshift.ll_gvar_from_constant,
+## [ts.s_JITState, self.annotation()],
+## [v_jitstate, v],
+## ts.s_ConstOrVar)
def convert_const(self, ll_value):
return ll_value
@@ -689,12 +1029,12 @@
def convert_from_to((r_from, r_to), v, llops):
assert r_from.lowleveltype == r_to.original_concretetype
- ts = llops.timeshifter
+ ts = llops.hrtyper
v_jitstate = llops.getjitstate()
return llops.genmixlevelhelpercall(rvalue.ll_fromvalue,
[ts.s_JITState, r_from.annotation()],
[v_jitstate, v],
- llops.timeshifter.s_RedBox)
+ ts.s_RedBox)
# ____________________________________________________________
Modified: pypy/dist/pypy/jit/timeshifter/rvalue.py
==============================================================================
--- pypy/dist/pypy/jit/timeshifter/rvalue.py (original)
+++ pypy/dist/pypy/jit/timeshifter/rvalue.py Thu Sep 21 11:30:27 2006
@@ -90,10 +90,9 @@
def ll_fromvalue(jitstate, value):
"Make a constant RedBox from a low-level value."
- rgenop = jitstate.curbuilder.rgenop
+ gv = ll_gv_fromvalue(jitstate, value)
T = lltype.typeOf(value)
- kind = rgenop.kindToken(T)
- gv = rgenop.genconst(value)
+ kind = jitstate.curbuilder.rgenop.kindToken(T)
cls = ll_redboxcls(T)
return cls(kind, gv)
@@ -104,10 +103,19 @@
cls = ll_redboxcls(T)
return cls(kind, gv)
+def ll_gv_fromvalue(jitstate, value):
+ rgenop = jitstate.curbuilder.rgenop
+ gv = rgenop.genconst(value)
+ return gv
+
def ll_getvalue(box, T):
"Return the content of a known-to-be-constant RedBox."
return box.genvar.revealconst(T)
+def ll_is_constant(box):
+ "Check if a red box is known to be constant."
+ return box.is_constant()
+
class IntRedBox(RedBox):
"A red box that contains a constant integer-like value."
Modified: pypy/dist/pypy/jit/timeshifter/test/test_timeshift.py
==============================================================================
--- pypy/dist/pypy/jit/timeshifter/test/test_timeshift.py (original)
+++ pypy/dist/pypy/jit/timeshifter/test/test_timeshift.py Thu Sep 21 11:30:27 2006
@@ -3,7 +3,7 @@
from pypy.jit.hintannotator.annotator import HintAnnotator
from pypy.jit.hintannotator.bookkeeper import HintBookkeeper
from pypy.jit.hintannotator.model import *
-from pypy.jit.timeshifter.timeshift import HintTimeshift
+from pypy.jit.timeshifter.rtyper import HintRTyper, originalconcretetype
from pypy.jit.timeshifter import rtimeshift, rvalue, rtyper as hintrtyper
from pypy.objspace.flow.model import summary
from pypy.rpython.lltypesystem import lltype, llmemory, rstr
@@ -94,12 +94,13 @@
backendoptimize=backendoptimize)
# make the timeshifted graphs
- htshift = HintTimeshift(ha, rtyper, self.RGenOp)
- fresh_jitstate = htshift.ll_fresh_jitstate
- finish_jitstate = htshift.ll_finish_jitstate
- RESTYPE = htshift.originalconcretetype(
- ha.translator.graphs[0].getreturnvar())
- htshift.timeshift()
+ hrtyper = HintRTyper(ha, rtyper, self.RGenOp)
+ hrtyper.specialize(view = conftest.option.view)
+
+ fresh_jitstate = hrtyper.ll_fresh_jitstate
+ finish_jitstate = hrtyper.ll_finish_jitstate
+ args_hs, hs_res = hrtyper.get_sig_hs(ha.translator.graphs[0])
+ RESTYPE = originalconcretetype(hs_res)
t = rtyper.annotator.translator
for graph in ha.translator.graphs:
checkgraph(graph)
@@ -122,9 +123,9 @@
argcolors = []
generate_code_args_s = []
- for v, llvalue in zip(graph1varargs, values):
+ for v, hs_arg, llvalue in zip(graph1varargs, args_hs, values):
s_var = annmodel.ll_to_annotation(llvalue)
- r = htshift.hrtyper.bindingrepr(v)
+ r = hrtyper.bindingrepr(v)
residual_v = r.residual_values(llvalue)
if len(residual_v) == 0:
color = "green"
@@ -132,9 +133,9 @@
else:
color = "red"
assert residual_v == [llvalue], "XXX for now"
- ARGTYPE = htshift.originalconcretetype(v)
+ ARGTYPE = originalconcretetype(hs_arg)
residual_argtypes.append(ARGTYPE)
- timeshifted_entrypoint_args_s.append(htshift.s_RedBox)
+ timeshifted_entrypoint_args_s.append(hrtyper.s_RedBox)
generate_code_args_s.append(annmodel.SomeBool())
argcolors.append(color)
generate_code_args_s.append(s_var)
@@ -143,9 +144,9 @@
graph1)
timeshifted_entrypoint = PseudoHighLevelCallable(
timeshifted_entrypoint_fnptr,
- [htshift.s_JITState]
+ [hrtyper.s_JITState]
+ timeshifted_entrypoint_args_s,
- htshift.s_JITState)
+ hrtyper.s_JITState)
FUNC = lltype.FuncType(residual_argtypes, RESTYPE)
argcolors = unrolling_iterable(argcolors)
self.argcolors = argcolors
@@ -216,7 +217,7 @@
self.ml_generate_code = ml_generate_code
## self.ml_call_residual_graph = ml_call_residual_graph
self.rtyper = rtyper
- self.htshift = htshift
+ self.hrtyper = hrtyper
self.annotate_interface_functions()
if conftest.option.view:
from pypy.translator.tool.graphpage import FlowGraphPage
@@ -228,7 +229,7 @@
return values
def annotate_interface_functions(self):
- annhelper = self.htshift.annhelper
+ annhelper = self.hrtyper.annhelper
RGenOp = self.RGenOp
ml_generate_code = self.ml_generate_code
## ml_call_residual_graph = self.ml_call_residual_graph
@@ -270,7 +271,7 @@
# now try to run the residual graph generated by the builder
residual_graph = ll_generated._obj.graph
- residual_graph.exceptiontransformed = self.htshift.exc_data_ptr
+ residual_graph.exceptiontransformed = self.hrtyper.exc_data_ptr
if conftest.option.view:
residual_graph.show()
self.insns = summary(residual_graph)
@@ -886,8 +887,19 @@
res = self.timeshift(ll_function, [3], [], policy=P_NOVIRTUAL)
assert res == 3
+ def test_green_call(self):
+ def ll_add_one(x):
+ return x+1
+ def ll_function(y):
+ z = ll_add_one(y)
+ z = hint(z, concrete=True)
+ return hint(z, variable=True)
+
+ res = self.timeshift(ll_function, [3], [0], policy=P_NOVIRTUAL)
+ assert res == 4
+ self.check_insns({})
+
def test_split_on_green_return(self):
- py.test.skip("in-progress")
def ll_two(x):
if x > 0:
return 17
@@ -895,7 +907,7 @@
return 22
def ll_function(x):
n = ll_two(x)
- return n+1
+ return hint(n+1, variable=True)
res = self.timeshift(ll_function, [-70], [])
assert res == 23
self.check_insns({'int_gt': 1})
Modified: pypy/dist/pypy/jit/timeshifter/vlist.py
==============================================================================
--- pypy/dist/pypy/jit/timeshifter/vlist.py (original)
+++ pypy/dist/pypy/jit/timeshifter/vlist.py Thu Sep 21 11:30:27 2006
@@ -8,7 +8,7 @@
def __init__(self, hrtyper, LIST):
RGenOp = hrtyper.RGenOp
- rtyper = hrtyper.timeshifter.rtyper
+ rtyper = hrtyper.rtyper
self.LIST = LIST
self.LISTPTR = lltype.Ptr(LIST)
self.ptrkind = RGenOp.kindToken(self.LISTPTR)
Modified: pypy/dist/pypy/rpython/rtyper.py
==============================================================================
--- pypy/dist/pypy/rpython/rtyper.py (original)
+++ pypy/dist/pypy/rpython/rtyper.py Thu Sep 21 11:30:27 2006
@@ -375,7 +375,7 @@
self.insert_link_conversions(extrablock)
def _convert_link(self, block, link):
- if link.exitcase is not None:
+ if link.exitcase is not None and link.exitcase != 'default':
if isinstance(block.exitswitch, Variable):
r_case = self.bindingrepr(block.exitswitch)
else:
Modified: pypy/dist/pypy/translator/backendopt/ssa.py
==============================================================================
--- pypy/dist/pypy/translator/backendopt/ssa.py (original)
+++ pypy/dist/pypy/translator/backendopt/ssa.py Thu Sep 21 11:30:27 2006
@@ -16,9 +16,7 @@
# [Block, blockvar, linkvar, linkvar, linkvar...]
opportunities = []
opportunities_with_const = []
- for block, links in mkentrymap(graph).items():
- if block is graph.startblock:
- continue
+ for block, links in mkinsideentrymap(graph).items():
assert links
for n, inputvar in enumerate(block.inputargs):
vars = [block, inputvar]
@@ -124,3 +122,95 @@
vct = [getattr(v, 'concretetype', None) for v in vlist]
assert vct == vct[:1] * len(vct), (
"variables called %s have mixed concretetypes: %r" % (vname, vct))
+
+# ____________________________________________________________
+
+def mkinsideentrymap(graph_or_blocks):
+ # graph_or_blocks can be a full FunctionGraph, or a mapping
+ # {block: reachable-from-outside-flag}.
+ if isinstance(graph_or_blocks, dict):
+ blocks = graph_or_blocks
+ entrymap = {}
+ for block in blocks:
+ for link in block.exits:
+ if link.target in blocks and not blocks[link.target]:
+ entrymap.setdefault(link.target, []).append(link)
+ return entrymap
+ else:
+ graph = graph_or_blocks
+ entrymap = mkentrymap(graph)
+ del entrymap[graph.startblock]
+ return entrymap
+
+def variables_created_in(block):
+ result = {}
+ for v in block.inputargs:
+ result[v] = True
+ for op in block.operations:
+ result[op.result] = True
+ return result
+
+
+def SSA_to_SSI(graph_or_blocks, annotator=None):
+ """Turn a number of blocks belonging to a flow graph into valid (i.e. SSI)
+ form, assuming that they are only in SSA form (i.e. they can use each
+ other's variables directly, without having to pass and rename them along
+ links).
+
+ 'graph_or_blocks' can be a graph, or just a dict that lists some blocks
+ from a graph, as follows: {block: reachable-from-outside-flag}.
+ """
+ from pypy.translator.unsimplify import copyvar
+
+ entrymap = mkinsideentrymap(graph_or_blocks)
+ builder = DataFlowFamilyBuilder(graph_or_blocks)
+ variable_families = builder.get_variable_families()
+ del builder
+
+ pending = [] # list of (block, var-used-but-not-defined)
+
+ for block in entrymap:
+ variables_created = variables_created_in(block)
+ variables_used = {}
+ for op in block.operations:
+ for v in op.args:
+ if isinstance(v, Variable):
+ variables_used[v] = True
+ if isinstance(block.exitswitch, Variable):
+ variables_used[v] = True
+ for link in block.exits:
+ for v in link.args:
+ if isinstance(v, Variable):
+ variables_used[v] = True
+
+ for v in variables_used:
+ if v not in variables_created:
+ pending.append((block, v))
+
+ while pending:
+ block, v = pending.pop()
+ v_rep = variable_families.find_rep(v)
+ variables_created = variables_created_in(block)
+ if v in variables_created:
+ continue # already ok
+ for w in variables_created:
+ w_rep = variable_families.find_rep(w)
+ if v_rep is w_rep:
+ # 'w' is in the same family as 'v', so we can simply
+ # reuse its value for 'v'
+ block.renamevariables({v: w})
+ break
+ else:
+ # didn't find it. Add it to all incoming links.
+ try:
+ links = entrymap[block]
+ except KeyError:
+ raise Exception("SSA_to_SSI failed: no way to give a value to"
+ " %r in %r" % (v, block))
+ w = copyvar(annotator, v)
+ variable_families.union(v, w)
+ block.renamevariables({v: w})
+ block.inputargs.append(w)
+ for link in links:
+ link.args.append(v)
+ pending.append((link.prevblock, v))
Modified: pypy/dist/pypy/translator/backendopt/test/test_ssa.py
==============================================================================
--- pypy/dist/pypy/translator/backendopt/test/test_ssa.py (original)
+++ pypy/dist/pypy/translator/backendopt/test/test_ssa.py Thu Sep 21 11:30:27 2006
@@ -1,6 +1,7 @@
from pypy.translator.backendopt.ssa import *
from pypy.translator.translator import TranslationContext
-from pypy.objspace.flow.model import flatten, Block
+from pypy.objspace.flow.model import flatten, Block, Link, Variable, Constant
+from pypy.objspace.flow.model import SpaceOperation
def test_data_flow_families():
@@ -49,3 +50,63 @@
allvars += [v.name for v in block.getvariables()]
# see comments above for where the 8 remaining variables are expected to be
assert len(dict.fromkeys(allvars)) == 8
+
+
+def test_SSA_to_SSI():
+ c = Variable('c')
+ x = Variable('x')
+ y = Variable('y')
+ b1 = Block([c])
+ b2 = Block([x])
+ b3 = Block([])
+
+ b2.operations.append(SpaceOperation('add', [x, c], y))
+ b2.exitswitch = y
+
+ b1.closeblock(Link([Constant(0)], b2))
+ b2.closeblock(Link([y], b2), Link([], b3))
+ b3.closeblock(Link([y, c], None))
+
+ SSA_to_SSI({b1: True, # reachable from outside
+ b2: False,
+ b3: False})
+
+ assert len(b1.inputargs) == 1
+ assert len(b2.inputargs) == 2
+ assert len(b3.inputargs) == 2
+
+ assert b2.inputargs == b2.operations[0].args
+ assert len(b1.exits[0].args) == 2
+ assert b1.exits[0].args[1] is c
+ assert len(b2.exits[0].args) == 2
+ assert b2.exits[0].args == [y, b2.inputargs[1]]
+ assert len(b2.exits[1].args) == 2
+ assert len(b3.exits[0].args) == 2
+
+ index = b3.inputargs.index(b3.exits[0].args[0])
+ assert b2.exits[1].args[index] is b2.operations[0].result
+
+ index = b3.inputargs.index(b3.exits[0].args[1])
+ assert b2.exits[1].args[index] is b2.inputargs[1]
+
+
+def test_SSA_to_SSI_2():
+ x = Variable('x')
+ y = Variable('y')
+ z = Variable('z')
+ b1 = Block([x])
+ b2 = Block([y])
+ b3 = Block([])
+
+ b3.operations.append(SpaceOperation('hello', [y], z))
+ b1.closeblock(Link([x], b2), Link([], b3))
+
+ SSA_to_SSI({b1: True, # reachable from outside
+ b2: False,
+ b3: False})
+
+ assert b1.inputargs == [x]
+ assert b2.inputargs == [y]
+ assert b3.inputargs == [b3.operations[0].args[0]]
+ assert b1.exits[0].args == [x]
+ assert b1.exits[1].args == [x]
Modified: pypy/dist/pypy/translator/simplify.py
==============================================================================
--- pypy/dist/pypy/translator/simplify.py (original)
+++ pypy/dist/pypy/translator/simplify.py Thu Sep 21 11:30:27 2006
@@ -63,10 +63,10 @@
if (len(link.target.exits) != 1 and
link.target.exitswitch != c_last_exception):
break
- assert link.target is not link.prevblock, (
- "the graph contains an empty infinite loop")
block1 = link.target
exit = block1.exits[0]
+ assert block1 is not exit.target, (
+ "the graph contains an empty infinite loop")
outputargs = []
for v in exit.args:
if isinstance(v, Variable):
More information about the Pypy-commit
mailing list