fix most loop tests
authorRobert Bradshaw <robertwb@math.washington.edu>
Wed, 25 Mar 2009 12:28:20 +0000 (05:28 -0700)
committerRobert Bradshaw <robertwb@math.washington.edu>
Wed, 25 Mar 2009 12:28:20 +0000 (05:28 -0700)
Cython/Compiler/Nodes.py
Cython/Compiler/Optimize.py
tests/run/range_optimisation_T203.pyx

index a5170317e9076850b80f78d0fae5db194efefc31..3275ba17977c99c36ba3bebe360e4397c66f1bde 100644 (file)
@@ -3840,6 +3840,7 @@ class ForFromStatNode(LoopNode, StatNode):
     #
     #  Used internally:
     #
+    #  from_range         bool
     #  is_py_target       bool
     #  loopvar_node       ExprNode (usually a NameNode or temp node)
     #  py_loopvar_node    PyTempNode or None
@@ -3848,6 +3849,7 @@ class ForFromStatNode(LoopNode, StatNode):
     is_py_target = False
     loopvar_node = None
     py_loopvar_node = None
+    from_range = False
 
     def analyse_declarations(self, env):
         self.target.analyse_target_declaration(env)
@@ -3866,13 +3868,15 @@ class ForFromStatNode(LoopNode, StatNode):
         else:
             self.bound1 = self.bound1.coerce_to_integer(env)
             self.bound2 = self.bound2.coerce_to_integer(env)
+        if not self.bound2.is_literal:
+            self.bound2 = self.bound2.coerce_to_temp(env)
         if self.step is not None:
             if isinstance(self.step, ExprNodes.UnaryMinusNode):
                 warning(self.step.pos, "Probable infinite loop in for-from-by statment. Consider switching the directions of the relations.", 2)
             self.step.analyse_types(env)
             self.step = self.step.coerce_to_integer(env)
-        if not (self.bound2.is_name or self.bound2.is_literal):
-            self.bound2 = self.bound2.coerce_to_temp(env)
+            if not self.step.is_literal:
+                self.step = self.step.coerce_to_temp(env)
         target_type = self.target.type
         if not (target_type.is_pyobject or target_type.is_numeric):
             error(self.target.pos,
@@ -3916,49 +3920,37 @@ class ForFromStatNode(LoopNode, StatNode):
             
     def generate_execution_code(self, code):
         old_loop_labels = code.new_loop_labels()
-        from_range = getattr(self, "from_range", False)
+        from_range = self.from_range
         self.bound1.generate_evaluation_code(code)
         self.bound2.generate_evaluation_code(code)
         offset, incop = self.relation_table[self.relation1]
-        if incop == "++":
-            decop = "--"
-        else:
-            decop = "++"
         if self.step is not None:
             self.step.generate_evaluation_code(code)
             step = self.step.result()
             incop = "%s=%s" % (incop[0], step)
-            decop = "%s=%s" % (decop[0], step)
-        loopvar_name = self.loopvar_node.result()
         if from_range:
-            range_bound = code.funcstate.allocate_temp(self.bound2.type, manage_ref=False)
-            code.putln("%s = %s;" % (range_bound, self.bound2.result()))
-            # Skip the loop entirely (and avoid assigning to the loopvar) if
-            # the loop is empty:
-            code.putln("if (%s%s %s %s) {" % (
-                self.bound1.result(), offset, self.relation2, range_bound
-                ))
+            loopvar_name = code.funcstate.allocate_temp(self.target.type, False)
         else:
-            range_bound = self.bound2.result()
+            loopvar_name = self.loopvar_node.result()
         code.putln(
             "for (%s = %s%s; %s %s %s; %s%s) {" % (
                 loopvar_name,
                 self.bound1.result(), offset,
-                loopvar_name, self.relation2, range_bound,
+                loopvar_name, self.relation2, self.bound2.result(),
                 loopvar_name, incop))
         if self.py_loopvar_node:
             self.py_loopvar_node.generate_evaluation_code(code)
             self.target.generate_assignment_code(self.py_loopvar_node, code)
+        elif from_range:
+            code.putln("%s = %s;" % (
+                            self.target.result(), loopvar_name))
         self.body.generate_execution_code(code)
         code.put_label(code.continue_label)
-        if from_range:
-            # Undo last increment to maintain Python semantics:
-            code.putln("} %s%s;" % (loopvar_name, decop))
-            # End the outer if statement:
-            code.putln("} /* end if */")
-            code.funcstate.release_temp(range_bound)
-        else:
-            code.putln("}")
+        if self.py_loopvar_node:
+            
+            self.py_loopvar_node.generate_evaluation_code(code)
+            self.target.generate_assignment_code(self.py_loopvar_node, code)
+        code.putln("}")
         break_label = code.break_label
         code.set_loop_labels(old_loop_labels)
         if self.else_clause:
@@ -3973,6 +3965,8 @@ class ForFromStatNode(LoopNode, StatNode):
         if self.step is not None:
             self.step.generate_disposal_code(code)
             self.step.free_temps(code)
+        if from_range:
+            code.funcstate.release_temp(loopvar_name)
     
     relation_table = {
         # {relop : (initial offset, increment op)}
index 8dc06e21015cf9a0cad4723283641a8845379cf0..e483494f8ac92bc10ebcc0273644057549226a79 100644 (file)
@@ -144,7 +144,6 @@ class IterationTransform(Visitor.VisitorTransform):
             relation2=relation2, bound2=bound2,
             step=step, body=node.body,
             else_clause=node.else_clause,
-            loopvar_node=node.target,
             from_range=True)
         return for_node
 
index 3e31bae32a177c764cfeae4feec361061556b73c..eadfde1288b095e530f391a4791f78c80cb4012e 100644 (file)
@@ -17,6 +17,11 @@ at 5
 at 7
 at 9
 9
+>>> for_from_range(-5, -10)
+range(-5)
+range(-5, -10)
+range(-5, -10, 2)
+100
 >>> for_from_bound_reassignment(5, 1)
 at 0
 at 1
@@ -62,8 +67,12 @@ at 3
 at 4
 5
 """
+cdef int get_bound(int m):
+    print "get_bound(%s)"%m
+    return m
+
 def for_from_range(a, b):
-    cdef int i
+    cdef int i = 100
     print "range(%s)" % a
     for i in range(a):
         print "at", i
@@ -75,26 +84,22 @@ def for_from_range(a, b):
         print "at", i
     return i
 
-cdef int get_bound(int m):
-    print "get_bound(%s)"%m
-    return m
-
 def for_from_bound_reassignment(int bound, int fake_bound):
-    cdef int i
+    cdef int i = 100
     for i from 0 <= i < bound:
         print "at", i
         bound = fake_bound
     return i
 
 def for_from_step_reassignment(int bound, int step, int fake_step):
-    cdef int i
+    cdef int i = 100
     for i from 0 <= i < bound by step:
         print "at", i
         step = fake_step
     return i
 
 def for_from_target_reassignment(int bound, int factor):
-    cdef int i
+    cdef int i = 100
     for i from 0 <= i < bound:
         print "at", i
         i *= factor
@@ -108,14 +113,14 @@ def for_from_py_target_reassignment(int bound, int factor):
     return i
 
 def for_in_target_reassignment(int bound, int factor):
-    cdef int i
+    cdef int i = 100
     for i in range(bound):
         print "at", i
         i *= factor
     return i
 
 def test_func(int n):
-    cdef int i
+    cdef int i = 100
     for i from 0 <= i < get_bound(n):
         print "at", i
     return i