Author: Richard Plangger <planri...@gmail.com>
Branch: gcstress-hypothesis
Changeset: r82986:c800d87fa7b4
Date: 2016-03-11 18:28 +0100
http://bitbucket.org/pypy/pypy/changeset/c800d87fa7b4/

Log:    working on a new strategy that cuts down the search space of control
        flow graphs to deterministic ones

diff --git a/rpython/jit/backend/llsupport/tl/code.py 
b/rpython/jit/backend/llsupport/tl/code.py
--- a/rpython/jit/backend/llsupport/tl/code.py
+++ b/rpython/jit/backend/llsupport/tl/code.py
@@ -7,6 +7,10 @@
         ctx.append_byte(self.BYTE_CODE)
 
     @classmethod
+    def splits_control_flow(self):
+        return False
+
+    @classmethod
     def filter_bytecode(self, stack):
         """ filter this byte code if the stack does
             not contain the right values on the stack.
@@ -210,9 +214,46 @@
     def __init__(self):
         pass
 
-def op_modifies_list(clazz):
-    """ NOT_RPYTHON """
-    return clazz in (DelList, InsertList)
+@requires_stack(INT_TYP)
+@leaves_on_stack()
+class CondJump(ByteCode):
+    BYTE_CODE = unique_code()
+
+    COND_EQ = 0
+    COND_LT = 1
+    COND_GT = 2
+    COND_LE = 3
+    COND_GE = 4
+    COND_ANY = 5
+
+    @requires_param(COND_TYP, INT_TYP)
+    def __init__(self, cond, offset):
+        self.cond = cond
+        self.offset = offset
+
+    def encode(self, ctx):
+        ctx.append_byte(self.BYTE_CODE)
+        ctx.append_byte(self.cond)
+        ctx.append_int(self.offset)
+
+    def splits_control_flow(self):
+        return True
+
+@requires_stack(LIST_TYP)
+@leaves_on_stack(LIST_TYP, INT_TYP)
+class LenList(ByteCode):
+    BYTE_CODE = unique_code()
+    def __init__(self):
+        pass
+
+
+#@requires_stack(INT_TYP) # TODO VAL_TYP)
+#@leaves_on_stack()
+#class ReturnFrame(ByteCode):
+#    BYTE_CODE = unique_code()
+#    def __init__(self):
+#        pass
+#
 
 BC_CLASSES = []
 BC_NUM_TO_CLASS = {}
@@ -223,47 +264,15 @@
         assert clazz.BYTE_CODE not in BC_NUM_TO_CLASS
         BC_NUM_TO_CLASS[clazz.BYTE_CODE] = clazz
 
-# remove comment one by one!
+BC_CLASSES.remove(CondJump)
 
-#@requires_stack()
-#@leaves_on_stack(INT_TYP)
-#class CondJump(ByteCode):
-#    BYTE_CODE = unique_code()
-#
-#    COND_EQ = 0
-#    COND_LT = 1
-#    COND_GT = 2
-#    COND_LE = 3
-#    COND_GE = 4
-#
-#    @requires_param(COND_TYP)
-#    def __init__(self, cond):
-#        self.cond = cond
-#
-#    def encode(self, ctx):
-#        ctx.append_byte(self.BYTE_CODE)
-#        ctx.append_byte(self.cond)
-#
-#@requires_stack()
-#@leaves_on_stack()
-#class Jump(ByteCode):
-#    BYTE_CODE = unique_code()
-#    def __init__(self):
-#        pass
-#
+# control flow byte codes
+BC_CF_CLASSES = [CondJump]
 
-#@requires_stack(LIST_TYP)
-#@leaves_on_stack(LIST_TYP, INT_TYP)
-#class LenList(ByteCode):
-#    BYTE_CODE = unique_code()
-#    def __init__(self):
-#        pass
-#
-#
-#@requires_stack(INT_TYP) # TODO VAL_TYP)
-#@leaves_on_stack()
-#class ReturnFrame(ByteCode):
-#    BYTE_CODE = unique_code()
-#    def __init__(self):
-#        pass
-#
+class ByteCodeControlFlow(object):
+    # see the deterministic control flow search startegy in
+    # test/code_strategies.py for what steps & byte_codes mean
+    def __init__(self):
+        self.blocks = []
+        self.steps = 0
+        self.byte_codes = 0
diff --git a/rpython/jit/backend/llsupport/tl/interp.py 
b/rpython/jit/backend/llsupport/tl/interp.py
--- a/rpython/jit/backend/llsupport/tl/interp.py
+++ b/rpython/jit/backend/llsupport/tl/interp.py
@@ -13,6 +13,9 @@
     def __init__(self, items):
         self.items = items
 
+    def size(self):
+        return len(self.items)
+
     def concat(self, space, w_lst):
         assert isinstance(w_lst, W_ListObject)
         return space.wrap(self.items + w_lst.items)
@@ -153,6 +156,22 @@
         w_lst = stack.peek(0)
         del w_lst.items[w_idx.value]
         # index error, just crash the machine!!
+    elif opcode == code.LenList.BYTE_CODE:
+        w_lst = stack.peek(0)
+        assert isinstance(w_lst, W_ListObject)
+        stack.append(space.wrap(w_lst.size()))
+    elif opcode == code.CondJump.BYTE_CODE:
+        cond = runpack('b', bytecode[i+1:i+2])
+        offset = runpack('i', bytecode[i+2:i+6])
+        w_int = stack.pop(0)
+        assert isinstance(w_lst, W_IntObject)
+        i += 5
+        if CondJump.should_jump(cond, w_int.value):
+            if offset < 0:
+                pass # TODO jit driver
+            # the new position is calculated at the end of
+            # this jump instruction!!
+            i += offset
     else:
         print("opcode %d is not implemented" % opcode)
         raise NotImplementedError
diff --git a/rpython/jit/backend/llsupport/tl/test/code_strategies.py 
b/rpython/jit/backend/llsupport/tl/test/code_strategies.py
--- a/rpython/jit/backend/llsupport/tl/test/code_strategies.py
+++ b/rpython/jit/backend/llsupport/tl/test/code_strategies.py
@@ -4,6 +4,7 @@
 from rpython.jit.backend.llsupport.tl import code, interp, stack
 from hypothesis.searchstrategy.collections import TupleStrategy, ListStrategy
 import hypothesis.internal.conjecture.utils as cu
+from collections import namedtuple
 
 def get_strategy_for(typ):
     if typ == code.INT_TYP:
@@ -107,7 +108,7 @@
 @composite
 def bytecode(draw, max_stack_size=4096):
     # get a stack that is the same for one test run
-    run_stack = draw(st.shared(st.just(stack.Stack(0)), 'stack2'))
+    run_stack = draw(st.shared(st.just(stack.Stack(0)), 'stack'))
 
     # get a byte code class, only allow what is valid for the run_stack
     clazzes = filter(lambda clazz: clazz.filter_bytecode(run_stack), 
code.BC_CLASSES)
@@ -124,3 +125,51 @@
 
     return inst
 
+class DeterministicControlFlowSearchStrategy(SearchStrategy):
+    """ This is flow graph search space is limited to deterministic
+        control flow. This means the execution of this program MUST
+        terminate in at most `max_steps`.
+
+        max/min_steps: one step is one execution in the interpreter loop
+        max_byte_codes: the amount of bytecodes the final program has
+    """
+
+    def __init__(self, stack, min_steps=1, max_steps=2**16, 
max_byte_codes=5000):
+        SearchStrategy.__init__(self)
+
+        self.stack = stack
+        self.max_steps = float(max_steps)
+        self.min_steps = min_steps
+        self.max_byte_codes = max_byte_codes
+
+        # self.element_strategy = one_of_strategies(strategies)
+
+    def validate(self):
+        pass
+        #self.element_strategy.validate()
+
+    def do_draw(self, data):
+        bccf = code.ByteCodeControlFlow()
+        result = []
+        while True:
+            stopping_value = 1 - 1.0 / (1 + self.average_length)
+            data.start_example()
+            more = cu.biased_coin(data, stopping_value)
+            if not more:
+                data.stop_example()
+                if len(result) < self.min_size:
+                    continue
+                else:
+                    break
+            value = data.draw(self.element_strategy)
+            data.stop_example()
+            result.append(value)
+        return bccf
+
+@st.defines_strategy
+def control_flow_graph(draw, stack=None, blocks):
+    if stack is None:
+        # get a stack that is the same for one test run
+        stack = stack.Stack(0)
+    return DeterministicControlFlowSearchStrategy(stack)
+
diff --git a/rpython/jit/backend/llsupport/tl/test/test_tl_interp.py 
b/rpython/jit/backend/llsupport/tl/test/test_tl_interp.py
--- a/rpython/jit/backend/llsupport/tl/test/test_tl_interp.py
+++ b/rpython/jit/backend/llsupport/tl/test/test_tl_interp.py
@@ -5,6 +5,8 @@
 from rpython.jit.backend.llsupport.tl.stack import Stack
 from rpython.jit.backend.llsupport.tl.test import code_strategies as st
 
+STD_SPACE = interp.Space()
+
 class TestByteCode(object):
     def test_load_str(self):
         c = code.Context()
@@ -28,7 +30,6 @@
 
     @given(data())
     def test_bytecode_class_generation(self, data):
-        space = interp.Space()
         stack = Stack(0)
         for i in range(10):
             clazz = data.draw(st.bytecode_class(stack))
@@ -36,13 +37,12 @@
 
     @given(data())
     def test_bytecode_class_generation_int(self, data):
-        space = interp.Space()
         stack = Stack(0)
-        stack.append(space.wrap(0))
+        stack.append(STD_SPACE.wrap(0))
         for i in range(10):
             clazz = data.draw(st.bytecode_class(stack))
             assert(clazz in self.DEFAULT_ACTION_CLASSES)
-        stack.append(space.wrap(0))
+        stack.append(STD_SPACE.wrap(0))
         for i in range(10):
             clazz = data.draw(st.bytecode_class(stack))
             assert(clazz in self.DEFAULT_ACTION_CLASSES + \
@@ -50,13 +50,12 @@
 
     @given(data())
     def test_bytecode_class_generation_str(self, data):
-        space = interp.Space()
         stack = Stack(0)
-        stack.append(space.wrap("hello"))
+        stack.append(STD_SPACE.wrap("hello"))
         for i in range(10):
             clazz = data.draw(st.bytecode_class(stack))
             assert(clazz in self.DEFAULT_ACTION_CLASSES)
-        stack.append(space.wrap("world"))
+        stack.append(STD_SPACE.wrap("world"))
         for i in range(10):
             clazz = data.draw(st.bytecode_class(stack))
             assert(clazz in self.DEFAULT_ACTION_CLASSES + \
@@ -64,20 +63,19 @@
 
     @given(data())
     def test_bytecode_class_generation_list(self, data):
-        space = interp.Space()
         stack = Stack(0)
-        stack.append(space.wrap([]))
-        stack.append(space.wrap(0))
+        stack.append(STD_SPACE.wrap([]))
+        stack.append(STD_SPACE.wrap(0))
         for i in range(10):
             clazz = data.draw(st.bytecode_class(stack))
             assert(clazz not in (code.InsertList, code.DelList))
-        stack.append(space.wrap([space.wrap(1)]))
-        stack.append(space.wrap(0))
+        stack.append(STD_SPACE.wrap([STD_SPACE.wrap(1)]))
+        stack.append(STD_SPACE.wrap(0))
         for i in range(10):
             clazz = data.draw(st.bytecode_class(stack))
             assert(clazz in self.DEFAULT_ACTION_CLASSES + \
                             (code.DelList, code.AppendList))
-        stack.append(space.wrap("haskell"))
+        stack.append(STD_SPACE.wrap("haskell"))
         for i in range(10):
             clazz = data.draw(st.bytecode_class(stack))
             assert(clazz in self.DEFAULT_ACTION_CLASSES + \
@@ -85,7 +83,6 @@
 
     @given(data())
     def test_empty_stack_no_list_op(self, data):
-        space = interp.Space()
         stack = Stack(0)
         for i in range(10):
             clazz = data.draw(st.bytecode_class(stack))
@@ -93,10 +90,26 @@
                                     code.AppendList, code.AddList,
                                     code.AddStr))
 
+    @given(data())
+    def test_control_flow_split(self, data):
+        stack = Stack(0)
+        cfg = data.draw(st.control_flow_graph(stack))
+        assert cfg.steps > 0
+        # assert that there is at least one block that ends with a cond. jump
+        assert any([isinstance(block[-1], CondJump) for block in cfg.blocks])
+
 class TestInterp(object):
 
     @given(st.basic_block(st.bytecode(), min_size=1))
     def test_execute_bytecode_block(self, bc_obj_list):
+        self.execute(bc_obj_list)
+
+    @given(st.control_flow_graph())
+    def test_execute_bytecode_block(self, cfg):
+        bc_obj_list = cfg.linearize()
+        self.execute(bc_obj_list)
+
+    def execute(self, bc_obj_list):
         bytecode, consts = code.Context().transform(bc_obj_list)
         space = interp.Space()
         pc = 0
_______________________________________________
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to