Author: Richard Plangger <planri...@gmail.com>
Branch: gcstress-hypothesis
Changeset: r83086:65a4e92ce40f
Date: 2016-03-15 11:31 +0100
http://bitbucket.org/pypy/pypy/changeset/65a4e92ce40f/

Log:    generating control flow using basic blocks, need conditions and
        loops

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
@@ -92,6 +92,12 @@
             code.append(struct.pack(typ, nmr))
         return ''.join(code)
 
+    def transform_blocks(self, blocks):
+        for block in blocks:
+            for code_obj in block.opcodes:
+                code_obj.encode(self)
+        return self.to_string(), self.consts
+
     def transform(self, code_objs):
         for code_obj in code_objs:
             code_obj.encode(self)
@@ -239,6 +245,14 @@
     def splits_control_flow(self):
         return True
 
+    @staticmethod
+    def should_jump(cond, value):
+        # TODO
+        if value == 0 and cond == 0:
+            return True
+        return False
+
+
 @requires_stack(LIST_TYP)
 @leaves_on_stack(LIST_TYP, INT_TYP)
 class LenList(ByteCode):
@@ -269,6 +283,15 @@
 # control flow byte codes
 BC_CF_CLASSES = [CondJump]
 
+class ByteCodeBlock(object):
+    def __init__(self, stack):
+        self.init_stack = stack.copy()
+        self.exit_stack = None
+        self.opcodes = []
+
+    def interp_steps(self):
+        return len(self.opcodes)
+
 class ByteCodeControlFlow(object):
     # see the deterministic control flow search startegy in
     # test/code_strategies.py for what steps & byte_codes mean
@@ -276,3 +299,35 @@
         self.blocks = []
         self.steps = 0
         self.byte_codes = 0
+
+    def interp_steps(self):
+        """ how many steps does the interpreter perform to
+            reach the end of the current control flow?
+        """
+        return self.steps
+
+    def linearize(self):
+        from rpython.jit.backend.llsupport.tl import code
+        ctx = code.Context()
+        bytecode, consts = ctx.transform_blocks(self.blocks)
+        return bytecode, consts
+
+    def generate_block(self, data, last_block, strat):
+        if last_block:
+            stack = last_block.init_stack
+        else:
+            from rpython.jit.backend.llsupport.tl.stack import Stack
+            stack = Stack(0)
+
+        bcb = ByteCodeBlock(stack)
+        opcodes = data.draw(strat.draw_from(stack, self))
+        if not opcodes:
+            return None
+        bcb.exit_stack = stack.copy()
+        bcb.opcodes = opcodes
+        self.steps += bcb.interp_steps()
+        self.byte_codes += len(opcodes)
+        self.blocks.append(bcb)
+        return bcb
+
+
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
@@ -161,17 +161,19 @@
         assert isinstance(w_lst, W_ListObject)
         stack.append(space.wrap(w_lst.size()))
     elif opcode == code.CondJump.BYTE_CODE:
+        assert i >= 0
         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)
+        w_int = stack.pop()
+        assert isinstance(w_int, W_IntObject)
         i += 5
-        if CondJump.should_jump(cond, w_int.value):
+        if code.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
+            assert i >= 0
     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
@@ -2,7 +2,9 @@
 from hypothesis.control import assume
 from hypothesis.strategies import composite
 from rpython.jit.backend.llsupport.tl import code, interp, stack
+from rpython.jit.backend.llsupport.tl.stack import Stack
 from hypothesis.searchstrategy.collections import TupleStrategy, ListStrategy
+from hypothesis.searchstrategy.strategies import SearchStrategy, 
one_of_strategies
 import hypothesis.internal.conjecture.utils as cu
 from collections import namedtuple
 
@@ -33,12 +35,12 @@
 
 def runtime_stack(min_size=0, average_size=5, max_size=4096, 
types=code.all_types):
     if max_size == 0:
-        return st.just(stack.Stack(0))
+        return st.just(Stack(0))
     stack_entries = st.lists(stack_entry(all_types), min_size=min_size,
                              average_size=average_size,
                              max_size=max_size)
     return stack_entries.map(lambda elems: \
-                                stack.Stack.from_items(STD_SPACE, elems))
+                                Stack.from_items(STD_SPACE, elems))
 
 def get_byte_code_class(num):
     return code.BC_NUM_TO_CLASS[num]
@@ -63,7 +65,6 @@
                 data.draw(self.element_strategy)
                 for _ in range(self.min_size)
             ]
-
         stopping_value = 1 - 1.0 / (1 + self.average_length)
         result = []
         while True:
@@ -94,9 +95,12 @@
 
 @st.defines_strategy
 def basic_block(strategy, min_size=1, average_size=8, max_size=128):
+    assert max_size >= 1
+    if average_size < max_size:
+        average_size = max_size//2
     return BasicBlockStrategy([strategy], min_size=min_size,
                               average_length=average_size,
-                              max_size=max_size)
+                              max_size=int(max_size))
 
 @st.defines_strategy
 def bytecode_class(stack):
@@ -106,9 +110,10 @@
 
 
 @composite
-def bytecode(draw, max_stack_size=4096):
+def bytecode(draw, run_stack=None):
     # get a stack that is the same for one test run
-    run_stack = draw(st.shared(st.just(stack.Stack(0)), 'stack'))
+    if run_stack is None:
+        run_stack = draw(st.shared(st.just(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)
@@ -134,42 +139,52 @@
         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):
+    def __init__(self, stack, min_steps=1, max_steps=2**16, 
max_byte_codes=4000):
         SearchStrategy.__init__(self)
 
         self.stack = stack
         self.max_steps = float(max_steps)
         self.min_steps = min_steps
+        self.average_steps = (self.max_steps - self.min_steps) / 2.0
         self.max_byte_codes = max_byte_codes
 
-        # self.element_strategy = one_of_strategies(strategies)
-
     def validate(self):
         pass
         #self.element_strategy.validate()
 
+    def draw_from(self, stack, bccf):
+        left = int(self.max_steps - bccf.interp_steps())
+        if left <= 0:
+            return st.just(None)
+        if left > 32:
+            left = 32
+        # either draw a normal basic block
+        strats = [basic_block(bytecode(stack), max_size=left)]
+        # or draw a loop
+        #strats.append(deterministic_loop(bytecode(stack)))
+        # or draw a conditional
+        #strats.append(conditional(bytecode(stack)))
+        return one_of_strategies(strats)
+
     def do_draw(self, data):
         bccf = code.ByteCodeControlFlow()
-        result = []
+        last_block = None
+        stopping_value = 1 - 1.0 / (1 + self.average_steps)
         while True:
-            stopping_value = 1 - 1.0 / (1 + self.average_length)
             data.start_example()
+            block = bccf.generate_block(data, last_block, self)
+            data.stop_example()
+            if block is None:
+                break # enough is enough!
             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)
+                break
         return bccf
 
 @st.defines_strategy
-def control_flow_graph(draw, stack=None, blocks):
+def control_flow_graph(stack=None):
     if stack is None:
         # get a stack that is the same for one test run
-        stack = stack.Stack(0)
+        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
@@ -101,16 +101,18 @@
 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)
+    def test_execute_block(self, bc_obj_list):
+        bytecode, consts = code.Context().transform(bc_obj_list)
+        self.execute(bytecode, consts)
 
     @given(st.control_flow_graph())
-    def test_execute_bytecode_block(self, cfg):
-        bc_obj_list = cfg.linearize()
-        self.execute(bc_obj_list)
+    @settings(perform_health_check=False, min_satisfying_examples=1000)
+    def test_execute_cfg(self, cfg):
+        print("execute_cfg: cfg with steps:", cfg.interp_steps())
+        bytecode, consts = cfg.linearize()
+        self.execute(bytecode, consts)
 
-    def execute(self, bc_obj_list):
-        bytecode, consts = code.Context().transform(bc_obj_list)
+    def execute(self, bytecode, consts):
         space = interp.Space()
         pc = 0
         end = len(bytecode)
diff --git a/rpython/jit/backend/llsupport/tl/test/zrpy_gc_hypo_test.py 
b/rpython/jit/backend/llsupport/tl/test/zrpy_gc_hypo_test.py
--- a/rpython/jit/backend/llsupport/tl/test/zrpy_gc_hypo_test.py
+++ b/rpython/jit/backend/llsupport/tl/test/zrpy_gc_hypo_test.py
@@ -1,5 +1,5 @@
 import py
-from hypothesis import given
+from hypothesis import given, settings
 from hypothesis.strategies import lists
 from rpython.tool.udir import udir
 from rpython.jit.metainterp.optimize import SpeculativeError
@@ -68,3 +68,13 @@
         if result != 0:
             raise Exception(("could not run program. returned %d"
                             " stderr:\n%s\nstdout:\n%s\n") % (result, err, 
out))
+
+    @given(st.control_flow_graph())
+    @settings(perform_health_check=False, min_satisfying_examples=1000)
+    def test_execute_cfg(self, cfg):
+        print "execute_cfg: cfg with steps:", cfg.interp_steps()
+        bytecode, consts = cfg.linearize()
+        result, out, err = self.execute(bytecode, consts)
+        if result != 0:
+            raise Exception(("could not run program. returned %d"
+                            " stderr:\n%s\nstdout:\n%s\n") % (result, err, 
out))
_______________________________________________
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to