Commits

Hakan Ardo  committed 40db680

allow (discarded) null valued fields to be genralized

  • Participants
  • Parent commits aa8f94d
  • Branches jit-usable_retrace_3

Comments (0)

Files changed (2)

File pypy/jit/metainterp/optimizeopt/virtualstate.py

     def make_guardable_generalization_of(self, other, value, optimizer):
         pass
 
+    def make_guardable_generalization_of_null(self, value, optimizer):
+        pass
+
     def generate_guards(self, other, box, cpu, extra_guards, renum):
         if self.generalization_of(other, renum, {}):
             return
         raise InvalidLoop('Generating guards for making the VirtualStates ' +
                           'at hand match have not been implemented')
 
-    def enum_forced_boxes(self, boxes, value, optimizer):
+    def enum_forced_boxes(self, boxes, value, optimizer, doforce):
         raise NotImplementedError
 
     def enum(self, virtual_state):
         assert len(self.fielddescrs) == len(self.fieldstate)
         assert len(other.fielddescrs) == len(other.fieldstate)
         assert isinstance(value, virtualize.AbstractVirtualStructValue)
-        if len(self.fielddescrs) != len(other.fielddescrs):
-            raise InvalidLoop('Cant combine virtuals with different numbers of fields.')
-        for i in range(len(self.fielddescrs)):
-            if other.fielddescrs[i] is not self.fielddescrs[i]:
-                raise InvalidLoop('Cant combine virtuals with different fields.')
-            new_field_value = self.fieldstate[i].make_guardable_generalization_of(other.fieldstate[i],
-                                                                        value.getfield(self.fielddescrs[i], None),
-                                                                        optimizer)
+
+        i = j = 0
+        while i < len(self.fielddescrs) and j < len(other.fielddescrs):
+            if other.fielddescrs[j] is self.fielddescrs[i]:
+                new_field_value = self.fieldstate[i].make_guardable_generalization_of(other.fieldstate[j],
+                                                       value.getfield(self.fielddescrs[i], None), optimizer)
+                if new_field_value:
+                    value.setfield(self.fielddescrs[i], new_field_value)
+                i += 1
+                j += 1
+            elif self.fielddescrs[i].sort_key() < other.fielddescrs[j].sort_key():
+                new_field_value = self.fieldstate[i].make_guardable_generalization_of_null(
+                                                       value.getfield(self.fielddescrs[i], None), optimizer)
+                if new_field_value:
+                    value.setfield(self.fielddescrs[i], new_field_value)
+                i += 1
+            else:
+                new_field_value = other.fieldstate[j].make_guardable_generalization_of_null(
+                                                       value.getfield(other.fielddescrs[j], None), optimizer)
+                if new_field_value:
+                    value.setfield(other.fielddescrs[j], new_field_value)
+                j += 1
+        while i < len(self.fielddescrs):
+            new_field_value = self.fieldstate[i].make_guardable_generalization_of_null(
+                                                   value.getfield(self.fielddescrs[i], None), optimizer)
             if new_field_value:
                 value.setfield(self.fielddescrs[i], new_field_value)
+            i += 1
+        while j < len(other.fielddescrs):
+            new_field_value = other.fieldstate[j].make_guardable_generalization_of_null(
+                                                   value.getfield(other.fielddescrs[j], None), optimizer)
+            if new_field_value:
+                value.setfield(other.fielddescrs[j], new_field_value)
+            j += 1
 
     def kill_null_fields(self):
         assert len(self.fielddescrs) == len(self.fieldstate)
     def _generalization_of(self, other):
         raise NotImplementedError
 
-    def enum_forced_boxes(self, boxes, value, optimizer):
+    def enum_forced_boxes(self, boxes, value, optimizer, doforce):
         if not isinstance(value, virtualize.AbstractVirtualStructValue):
             raise BadVirtualState
         if not value.is_virtual():
             raise BadVirtualState
         for i in range(len(self.fielddescrs)):
-            try:
-                v = value._fields[self.fielddescrs[i]]
-            except KeyError:
-                raise BadVirtualState
+            v = value.getfield(self.fielddescrs[i], None)
+            if v is None:
+                v = optimizer.new_const(self.fielddescrs[i])
             s = self.fieldstate[i]
             if s.position > self.position:
-                s.enum_forced_boxes(boxes, v, optimizer)
+                s.enum_forced_boxes(boxes, v, optimizer, doforce)
 
     def _enum(self, virtual_state):
         for s in self.fieldstate:
         return (isinstance(other, VArrayStateInfo) and
             self.arraydescr is other.arraydescr)
 
-    def enum_forced_boxes(self, boxes, value, optimizer):
+    def enum_forced_boxes(self, boxes, value, optimizer, doforce):
         if not isinstance(value, virtualize.VArrayValue):
             raise BadVirtualState
         if not value.is_virtual():
                 raise BadVirtualState
             s = self.fieldstate[i]
             if s.position > self.position:
-                s.enum_forced_boxes(boxes, v, optimizer)
+                s.enum_forced_boxes(boxes, v, optimizer, doforce)
 
     def _enum(self, virtual_state):
         for s in self.fieldstate:
         for s in self.fieldstate:
             s.enum(virtual_state)
 
-    def enum_forced_boxes(self, boxes, value, optimizer):
+    def enum_forced_boxes(self, boxes, value, optimizer, doforce):
         if not isinstance(value, virtualize.VArrayStructValue):
             raise BadVirtualState
         if not value.is_virtual():
                     raise BadVirtualState
                 s = self.fieldstate[p]
                 if s.position > self.position:
-                    s.enum_forced_boxes(boxes, v, optimizer)
+                    s.enum_forced_boxes(boxes, v, optimizer, doforce)
                 p += 1
 
     def debug_header(self, indent):
             optimizer.make_equal_to(box, v, True)
             return v
 
+    def make_guardable_generalization_of_null(self, value, optimizer):
+        box = value.get_key_box()
+        if isinstance(box, Const):
+            box = box.clonebox()
+        v = OptValue(box)
+        optimizer.make_equal_to(box, v, True)
+        return v
+
     def _generate_guards(self, other, box, cpu, extra_guards):
         if not isinstance(other, NotVirtualStateInfo):
             raise InvalidLoop('The VirtualStates does not match as a ' +
             import pdb; pdb.set_trace()
             raise NotImplementedError
 
-    def enum_forced_boxes(self, boxes, value, optimizer):
+    def enum_forced_boxes(self, boxes, value, optimizer, doforce):
         if self.level == LEVEL_CONSTANT:
             return
         assert 0 <= self.position_in_notvirtuals
-        if optimizer:
+        if doforce:
             box = value.force_box(optimizer)
         else:
             if value.is_virtual():
         # which might change the virtual state if the box appear in more
         # than one place among the inputargs.
         for i in range(len(values)):
-            self.state[i].enum_forced_boxes(inputargs, values[i], optimizer)
+            self.state[i].enum_forced_boxes(inputargs, values[i], optimizer, True)
         for i in range(len(values)):
-            self.state[i].enum_forced_boxes(inputargs, values[i], None)
+            self.state[i].enum_forced_boxes(inputargs, values[i], optimizer, False)
 
         if keyboxes:
             for i in range(len(values)):

File pypy/jit/metainterp/test/test_virtualstate.py

         o = self.optimizer
         self.combine([o.node1], [o.subnode1], InvalidLoop)
 
+    def test_boxed_int_zero1(self):
+        o = self.optimizer
+        self.setfield(o.node1, o.descr1, o.const_int1)
+        self.setfield(o.node2, o.descr1, o.const_int0)
+        self.combine([o.node1], [o.node1], [Virtual(o.node_class, {o.descr1: Const(1)})])
+
+    def test_boxed_int_zero2(self):
+        o = self.optimizer
+        self.setfield(o.node1, o.descr1, o.const_int1)
+        self.setfield(o.node2, o.descr1, o.const_int0)
+        self.combine([o.node2], [o.node2], [Virtual(o.node_class, {})])
+
+    def test_boxed_int_zero3(self):
+        o = self.optimizer
+        self.setfield(o.node1, o.descr1, o.const_int1)
+        self.setfield(o.node2, o.descr1, o.const_int0)
+        self.combine([o.node1], [o.node2], [Virtual(o.node_class, {o.descr1: Unknown})])
+
+    def test_boxed_int_zero4(self):
+        o = self.optimizer
+        self.setfield(o.node1, o.descr1, o.const_int1)
+        self.setfield(o.node2, o.descr1, o.const_int0)
+        self.combine([o.node2], [o.node1], [Virtual(o.node_class, {o.descr1: Unknown})])
+
+    def test_three_boxed_int_zero(self):
+        o = self.optimizer
+        for consts1 in itertools.permutations([o.const_int0, o.const_int1, o.const_int2]):
+            for consts2 in itertools.permutations([o.const_int0, o.const_int1, o.const_int2]):
+                self.setfield(o.node1, o.descr1, consts1[0])
+                self.setfield(o.node1, o.descr2, consts1[1])
+                self.setfield(o.node1, o.descr3, consts1[2])
+                self.setfield(o.node2, o.descr1, consts2[0])
+                self.setfield(o.node2, o.descr2, consts2[1])
+                self.setfield(o.node2, o.descr3, consts2[2])
+                flds = {d: Const(c1.value) if c1 is c2 else Unknown 
+                        for d, c1, c2 in zip([o.descr1, o.descr2, o.descr3], consts1, consts2)}
+                for d in flds.keys():
+                    try:
+                        if flds[d].value.value == 0:
+                            del flds[d]
+                    except AttributeError:
+                        pass
+                self.combine([o.node1], [o.node2], [Virtual(o.node_class, flds)])
+
     def test_currently_unsupported_case(self):
         o = self.optimizer
         self.combine([o.array1], [o.array2], InvalidLoop)