Commits

Hakan Ardo committed 52db1aa Merge

hg merge default

Comments (0)

Files changed (26)

pypy/doc/confrest.py

             html.a("documentation", href=self.get_doclink("docindex.html"),
                    class_="menu"),
             " ", 
-            html.a("svn", href="https://codespeak.net/viewvc/pypy/trunk/",
+            html.a("hg", href="https://bitbucket.org/pypy/pypy",
                    class_="menu"),
             " ", 
             html.a("issues",

pypy/doc/how-to-release.txt

 * write release announcement pypy/doc/release-x.y(.z).txt
   the release announcement should contain a direct link to the download page
 * update pypy.org (under extradoc/pypy.org), rebuild and commit
+
+* update http://codespeak.net/pypy/trunk:
+   code0> + chmod -R yourname:users /www/codespeak.net/htdocs/pypy/trunk
+   local> cd ..../pypy/doc && py.test
+   local> cd ..../pypy
+   local> rsync -az doc codespeak.net:/www/codespeak.net/htdocs/pypy/trunk/pypy/
+
 * post announcement on morepypy.blogspot.com
 * send announcements to pypy-dev, python-list,
   python-announce, python-dev ...

pypy/interpreter/baseobjspace.py

 
     def setbuiltinmodule(self, importname):
         """NOT_RPYTHON. load a lazy pypy/module and put it into sys.modules"""
-        import sys
-
         fullname = "pypy.module.%s" % importname
 
         Module = __import__(fullname,

pypy/jit/backend/llsupport/regalloc.py

         except KeyError:
             return self.frame_manager.loc(box)
 
-    def return_constant(self, v, forbidden_vars=[], selected_reg=None,
-                        imm_fine=True):
-        """ Return the location of the constant v.  If 'imm_fine' is False,
-        or if 'selected_reg' is not None, it will first load its value into
-        a register.  See 'force_allocate_reg' for the meaning of 'selected_reg'
-        and 'forbidden_vars'.
+    def return_constant(self, v, forbidden_vars=[], selected_reg=None):
+        """ Return the location of the constant v.  If 'selected_reg' is
+        not None, it will first load its value into this register.
         """
         self._check_type(v)
         assert isinstance(v, Const)
-        if selected_reg or not imm_fine:
-            # this means we cannot have it in IMM, eh
+        immloc = self.convert_to_imm(v)
+        if selected_reg:
             if selected_reg in self.free_regs:
-                self.assembler.regalloc_mov(self.convert_to_imm(v), selected_reg)
+                self.assembler.regalloc_mov(immloc, selected_reg)
                 return selected_reg
-            if selected_reg is None and self.free_regs:
-                loc = self.free_regs[-1]
-                self.assembler.regalloc_mov(self.convert_to_imm(v), loc)
-                return loc
             loc = self._spill_var(v, forbidden_vars, selected_reg)
             self.free_regs.append(loc)
-            self.assembler.regalloc_mov(self.convert_to_imm(v), loc)
+            self.assembler.regalloc_mov(immloc, loc)
             return loc
-        return self.convert_to_imm(v)
+        return immloc
 
     def make_sure_var_in_reg(self, v, forbidden_vars=[], selected_reg=None,
-                             imm_fine=True, need_lower_byte=False):
+                             need_lower_byte=False):
         """ Make sure that an already-allocated variable v is in some
-        register.  Return the register.  See 'return_constant' and
-        'force_allocate_reg' for the meaning of the optional arguments.
+        register.  Return the register.  See 'force_allocate_reg' for
+        the meaning of the optional arguments.
         """
         self._check_type(v)
         if isinstance(v, Const):
-            return self.return_constant(v, forbidden_vars, selected_reg,
-                                        imm_fine)
+            return self.return_constant(v, forbidden_vars, selected_reg)
         
         prev_loc = self.loc(v)
         loc = self.force_allocate_reg(v, forbidden_vars, selected_reg,
         self._check_type(result_v)
         self._check_type(v)
         if isinstance(v, Const):
-            loc = self.make_sure_var_in_reg(v, forbidden_vars,
-                                            imm_fine=False)
-            # note that calling make_sure_var_in_reg with imm_fine=False
-            # will not allocate place in reg_bindings, we need to do it
-            # on our own
+            if self.free_regs:
+                loc = self.free_regs.pop()
+            else:
+                loc = self._spill_var(v, forbidden_vars, None)
+            self.assembler.regalloc_mov(self.convert_to_imm(v), loc)
             self.reg_bindings[result_v] = loc
-            self.free_regs = [reg for reg in self.free_regs if reg is not loc]
             return loc
         if v not in self.reg_bindings:
             prev_loc = self.frame_manager.loc(v)

pypy/jit/backend/llsupport/test/test_regalloc.py

         rm = RegisterManager(longevity, assembler=asm,
                              frame_manager=fm)
         rm.next_instruction()
-        loc = rm.return_constant(ConstInt(0), imm_fine=False)
-        assert isinstance(loc, FakeReg)
         loc = rm.return_constant(ConstInt(1), selected_reg=r1)
         assert loc is r1
         loc = rm.return_constant(ConstInt(1), selected_reg=r1)
         assert loc is r1
-        loc = rm.return_constant(ConstInt(1), imm_fine=True)
+        loc = rm.return_constant(ConstInt(1))
         assert isinstance(loc, ConstInt)
         for box in boxes[:-1]:
             rm.force_allocate_reg(box)
-        assert len(asm.moves) == 3
-        loc = rm.return_constant(ConstInt(1), imm_fine=False)
-        assert isinstance(loc, FakeReg)
-        assert len(asm.moves) == 5
-        assert len(rm.reg_bindings) == 3
+        assert len(asm.moves) == 2       # Const(1) -> r1, twice
+        assert len(rm.reg_bindings) == 4
+        rm._check_invariants()
 
     def test_force_result_in_reg_const(self):
         boxes, longevity = boxes_and_longevity(2)

pypy/jit/backend/test/runner_test.py

         for i in range(1, len(fboxes)):
             assert self.cpu.get_latest_value_float(i) == 13.5 + 6.73 * i
 
+    def test_integers_and_guards(self):
+        for opname, compare in [
+            (rop.INT_LT, lambda x, y: x < y),
+            (rop.INT_LE, lambda x, y: x <= y),
+            (rop.INT_EQ, lambda x, y: x == y),
+            (rop.INT_NE, lambda x, y: x != y),
+            (rop.INT_GT, lambda x, y: x > y),
+            (rop.INT_GE, lambda x, y: x >= y),
+            ]:
+            for opguard, guard_case in [
+                (rop.GUARD_FALSE, False),
+                (rop.GUARD_TRUE,  True),
+                ]:
+                for combinaison in ["bb", "bc", "cb"]:
+                    #
+                    if combinaison[0] == 'b':
+                        ibox1 = BoxInt()
+                    else:
+                        ibox1 = ConstInt(-42)
+                    if combinaison[1] == 'b':
+                        ibox2 = BoxInt()
+                    else:
+                        ibox2 = ConstInt(-42)
+                    b1 = BoxInt()
+                    faildescr1 = BasicFailDescr(1)
+                    faildescr2 = BasicFailDescr(2)
+                    inputargs = [ib for ib in [ibox1, ibox2]
+                                    if isinstance(ib, BoxInt)]
+                    operations = [
+                        ResOperation(opname, [ibox1, ibox2], b1),
+                        ResOperation(opguard, [b1], None, descr=faildescr1),
+                        ResOperation(rop.FINISH, [], None, descr=faildescr2),
+                        ]
+                    operations[-2].setfailargs([])
+                    looptoken = LoopToken()
+                    self.cpu.compile_loop(inputargs, operations, looptoken)
+                    #
+                    cpu = self.cpu
+                    for test1 in [-65, -42, -11]:
+                        if test1 == -42 or combinaison[0] == 'b':
+                            for test2 in [-65, -42, -11]:
+                                if test2 == -42 or combinaison[1] == 'b':
+                                    n = 0
+                                    if combinaison[0] == 'b':
+                                        cpu.set_future_value_int(n, test1)
+                                        n += 1
+                                    if combinaison[1] == 'b':
+                                        cpu.set_future_value_int(n, test2)
+                                        n += 1
+                                    fail = cpu.execute_token(looptoken)
+                                    #
+                                    expected = compare(test1, test2)
+                                    expected ^= guard_case
+                                    assert fail.identifier == 2 - expected
+
+    def test_floats_and_guards(self):
+        if not self.cpu.supports_floats:
+            py.test.skip("requires floats")
+        for opname, compare in [
+            (rop.FLOAT_LT, lambda x, y: x < y),
+            (rop.FLOAT_LE, lambda x, y: x <= y),
+            (rop.FLOAT_EQ, lambda x, y: x == y),
+            (rop.FLOAT_NE, lambda x, y: x != y),
+            (rop.FLOAT_GT, lambda x, y: x > y),
+            (rop.FLOAT_GE, lambda x, y: x >= y),
+            ]:
+            for opguard, guard_case in [
+                (rop.GUARD_FALSE, False),
+                (rop.GUARD_TRUE,  True),
+                ]:
+                for combinaison in ["bb", "bc", "cb"]:
+                    #
+                    if combinaison[0] == 'b':
+                        fbox1 = BoxFloat()
+                    else:
+                        fbox1 = ConstFloat(-4.5)
+                    if combinaison[1] == 'b':
+                        fbox2 = BoxFloat()
+                    else:
+                        fbox2 = ConstFloat(-4.5)
+                    b1 = BoxInt()
+                    faildescr1 = BasicFailDescr(1)
+                    faildescr2 = BasicFailDescr(2)
+                    inputargs = [fb for fb in [fbox1, fbox2]
+                                    if isinstance(fb, BoxFloat)]
+                    operations = [
+                        ResOperation(opname, [fbox1, fbox2], b1),
+                        ResOperation(opguard, [b1], None, descr=faildescr1),
+                        ResOperation(rop.FINISH, [], None, descr=faildescr2),
+                        ]
+                    operations[-2].setfailargs([])
+                    looptoken = LoopToken()
+                    self.cpu.compile_loop(inputargs, operations, looptoken)
+                    #
+                    cpu = self.cpu
+                    nan = 1e200 * 1e200
+                    nan /= nan
+                    for test1 in [-6.5, -4.5, -2.5, nan]:
+                        if test1 == -4.5 or combinaison[0] == 'b':
+                            for test2 in [-6.5, -4.5, -2.5, nan]:
+                                if test2 == -4.5 or combinaison[1] == 'b':
+                                    n = 0
+                                    if combinaison[0] == 'b':
+                                        cpu.set_future_value_float(n, test1)
+                                        n += 1
+                                    if combinaison[1] == 'b':
+                                        cpu.set_future_value_float(n, test2)
+                                        n += 1
+                                    fail = cpu.execute_token(looptoken)
+                                    #
+                                    expected = compare(test1, test2)
+                                    expected ^= guard_case
+                                    assert fail.identifier == 2 - expected
+
     def test_unused_result_int(self):
         # test pure operations on integers whose result is not used
         from pypy.jit.metainterp.test.test_executor import get_int_tests

pypy/jit/backend/x86/assembler.py

                                          X86_64_XMM_SCRATCH_REG,
                                          RegLoc, StackLoc, ConstFloatLoc,
                                          ImmedLoc, AddressLoc, imm,
-                                         imm0, imm1)
+                                         imm0, imm1, FloatImmedLoc)
 
 from pypy.rlib.objectmodel import we_are_translated, specialize
 from pypy.jit.backend.x86 import rx86, regloc, codebuf
             tok.faildescr._x86_adr_jump_offset = addr
             relative_target = tok.pos_recovery_stub - (tok.pos_jump_offset + 4)
             assert rx86.fits_in_32bits(relative_target)
-            p = rffi.cast(rffi.INTP, addr)
-            p[0] = rffi.cast(rffi.INT, relative_target)
+            #
+            mc = codebuf.MachineCodeBlockWrapper()
+            mc.writeimm32(relative_target)
+            mc.copy_to_raw_memory(addr)
 
     def get_asmmemmgr_blocks(self, looptoken):
         clt = looptoken.compiled_loop_token
             self.mc.MOVZX8_rr(result_loc.value, rl.value)
         return genop_cmp
 
-    def _cmpop_float(cond, is_ne=False):
+    def _cmpop_float(cond, rev_cond, is_ne=False):
         def genop_cmp(self, op, arglocs, result_loc):
-            self.mc.UCOMISD(arglocs[0], arglocs[1])
+            if isinstance(arglocs[0], RegLoc):
+                self.mc.UCOMISD(arglocs[0], arglocs[1])
+                checkcond = cond
+            else:
+                self.mc.UCOMISD(arglocs[1], arglocs[0])
+                checkcond = rev_cond
+
             tmp1 = result_loc.lowest8bits()
             if IS_X86_32:
                 tmp2 = result_loc.higher8bits()
             elif IS_X86_64:
                 tmp2 = X86_64_SCRATCH_REG.lowest8bits()
 
-            self.mc.SET_ir(rx86.Conditions[cond], tmp1.value)
+            self.mc.SET_ir(rx86.Conditions[checkcond], tmp1.value)
             if is_ne:
                 self.mc.SET_ir(rx86.Conditions['P'], tmp2.value)
                 self.mc.OR8_rr(tmp1.value, tmp2.value)
                     self.implement_guard(guard_token, false_cond)
         return genop_cmp_guard
 
-    def _cmpop_guard_float(cond, false_cond, need_jp):
+    def _cmpop_guard_float(cond, rev_cond, false_cond, false_rev_cond):
+        need_direct_jp = 'A' not in cond
+        need_rev_jp = 'A' not in rev_cond
         def genop_cmp_guard_float(self, op, guard_op, guard_token, arglocs,
                                   result_loc):
             guard_opnum = guard_op.getopnum()
-            self.mc.UCOMISD(arglocs[0], arglocs[1])
+            if isinstance(arglocs[0], RegLoc):
+                self.mc.UCOMISD(arglocs[0], arglocs[1])
+                checkcond = cond
+                checkfalsecond = false_cond
+                need_jp = need_direct_jp
+            else:
+                self.mc.UCOMISD(arglocs[1], arglocs[0])
+                checkcond = rev_cond
+                checkfalsecond = false_rev_cond
+                need_jp = need_rev_jp
             if guard_opnum == rop.GUARD_FALSE:
                 if need_jp:
                     self.mc.J_il8(rx86.Conditions['P'], 6)
-                self.implement_guard(guard_token, cond)
+                self.implement_guard(guard_token, checkcond)
             else:
                 if need_jp:
                     self.mc.J_il8(rx86.Conditions['P'], 2)
-                    self.mc.J_il8(rx86.Conditions[cond], 5)
+                    self.mc.J_il8(rx86.Conditions[checkcond], 5)
                     self.implement_guard(guard_token)
                 else:
-                    self.implement_guard(guard_token, false_cond)
+                    self.implement_guard(guard_token, checkfalsecond)
         return genop_cmp_guard_float
 
     def _emit_call(self, x, arglocs, start=0, tmp=eax):
     genop_ptr_eq = genop_int_eq
     genop_ptr_ne = genop_int_ne
 
-    genop_float_lt = _cmpop_float('B')
-    genop_float_le = _cmpop_float('BE')
-    genop_float_ne = _cmpop_float('NE', is_ne=True)
-    genop_float_eq = _cmpop_float('E')
-    genop_float_gt = _cmpop_float('A')
-    genop_float_ge = _cmpop_float('AE')
+    genop_float_lt = _cmpop_float('B', 'A')
+    genop_float_le = _cmpop_float('BE', 'AE')
+    genop_float_ne = _cmpop_float('NE', 'NE', is_ne=True)
+    genop_float_eq = _cmpop_float('E', 'E')
+    genop_float_gt = _cmpop_float('A', 'B')
+    genop_float_ge = _cmpop_float('AE', 'BE')
 
     genop_uint_gt = _cmpop("A", "B")
     genop_uint_lt = _cmpop("B", "A")
     genop_guard_uint_le = _cmpop_guard("BE", "AE", "A", "B")
     genop_guard_uint_ge = _cmpop_guard("AE", "BE", "B", "A")
 
-    genop_guard_float_lt = _cmpop_guard_float("B", "AE", True)
-    genop_guard_float_le = _cmpop_guard_float("BE", "A", True)
-    genop_guard_float_eq = _cmpop_guard_float("E", "NE", True)
-    genop_guard_float_gt = _cmpop_guard_float("A", "BE", False)
-    genop_guard_float_ge = _cmpop_guard_float("AE", "B", False)
+    genop_guard_float_lt = _cmpop_guard_float("B", "A", "AE","BE")
+    genop_guard_float_le = _cmpop_guard_float("BE","AE", "A", "B")
+    genop_guard_float_eq = _cmpop_guard_float("E", "E", "NE","NE")
+    genop_guard_float_gt = _cmpop_guard_float("A", "B", "BE","AE")
+    genop_guard_float_ge = _cmpop_guard_float("AE","BE", "B", "A")
 
     def genop_guard_float_ne(self, op, guard_op, guard_token, arglocs, result_loc):
         guard_opnum = guard_op.getopnum()
-        self.mc.UCOMISD(arglocs[0], arglocs[1])
+        if isinstance(arglocs[0], RegLoc):
+            self.mc.UCOMISD(arglocs[0], arglocs[1])
+        else:
+            self.mc.UCOMISD(arglocs[1], arglocs[0])
         if guard_opnum == rop.GUARD_TRUE:
             self.mc.J_il8(rx86.Conditions['P'], 6)
             self.implement_guard(guard_token, 'E')
             self.mc.MOV16(dest_addr, value_loc)
         elif size == 4:
             self.mc.MOV32(dest_addr, value_loc)
-        elif IS_X86_64 and size == 8:
-            self.mc.MOV(dest_addr, value_loc)
+        elif size == 8:
+            if IS_X86_64:
+                self.mc.MOV(dest_addr, value_loc)
+            else:
+                assert isinstance(value_loc, FloatImmedLoc)
+                self.mc.MOV(dest_addr, value_loc.low_part_loc())
+                self.mc.MOV(dest_addr.add_offset(4), value_loc.high_part_loc())
         else:
             not_implemented("save_into_mem size = %d" % size)
 
             cls = self.cpu.gc_ll_descr.has_write_barrier_class()
             assert cls is not None and isinstance(descr, cls)
         loc_base = arglocs[0]
-        self.mc.TEST8_mi((loc_base.value, descr.jit_wb_if_flag_byteofs),
-                descr.jit_wb_if_flag_singlebyte)
+        if isinstance(loc_base, RegLoc):
+            self.mc.TEST8_mi((loc_base.value, descr.jit_wb_if_flag_byteofs),
+                             descr.jit_wb_if_flag_singlebyte)
+        else:
+            assert isinstance(loc_base, ImmedLoc)
+            self.mc.TEST8_ji(loc_base.value + descr.jit_wb_if_flag_byteofs,
+                             descr.jit_wb_if_flag_singlebyte)
         self.mc.J_il8(rx86.Conditions['Z'], 0) # patched later
         jz_location = self.mc.get_relative_pos()
         # the following is supposed to be the slow path, so whenever possible

pypy/jit/backend/x86/regalloc.py

 
 import os
 from pypy.jit.metainterp.history import (Box, Const, ConstInt, ConstPtr,
-                                         ResOperation, BoxPtr,
+                                         ResOperation, BoxPtr, ConstFloat,
                                          LoopToken, INT, REF, FLOAT)
 from pypy.jit.backend.x86.regloc import *
 from pypy.rpython.lltypesystem import lltype, ll2ctypes, rffi, rstr
                 self.possibly_free_var(var)
 
     def make_sure_var_in_reg(self, var, forbidden_vars=[],
-                             selected_reg=None, imm_fine=True,
-                             need_lower_byte=False):
+                             selected_reg=None, need_lower_byte=False):
         if var.type == FLOAT:
-            # always pass imm_fine=False for now in this case
+            if isinstance(var, ConstFloat):
+                return FloatImmedLoc(var.getfloat())
             return self.xrm.make_sure_var_in_reg(var, forbidden_vars,
-                                                 selected_reg, False,
-                                                 need_lower_byte)
+                                                 selected_reg, need_lower_byte)
         else:
             return self.rm.make_sure_var_in_reg(var, forbidden_vars,
-                                                selected_reg, imm_fine,
-                                                need_lower_byte)
+                                                selected_reg, need_lower_byte)
 
     def force_allocate_reg(self, var, forbidden_vars=[], selected_reg=None,
                            need_lower_byte=False):
     consider_float_truediv = _consider_float_op
 
     def _consider_float_cmp(self, op, guard_op):
-        args = op.getarglist()
-        loc0 = self.xrm.make_sure_var_in_reg(op.getarg(0), args,
-                                             imm_fine=False)
-        loc1 = self.xrm.loc(op.getarg(1))
-        arglocs = [loc0, loc1]
+        vx = op.getarg(0)
+        vy = op.getarg(1)
+        arglocs = [self.loc(vx), self.loc(vy)]
+        if not (isinstance(arglocs[0], RegLoc) or
+                isinstance(arglocs[1], RegLoc)):
+            if isinstance(vx, Const):
+                arglocs[1] = self.xrm.make_sure_var_in_reg(vy)
+            else:
+                arglocs[0] = self.xrm.make_sure_var_in_reg(vx)
         self.xrm.possibly_free_vars_for_op(op)
         if guard_op is None:
             res = self.rm.force_allocate_reg(op.result, need_lower_byte=True)
         self.xrm.possibly_free_var(op.getarg(0))
 
     def consider_cast_float_to_int(self, op):
-        loc0 = self.xrm.make_sure_var_in_reg(op.getarg(0), imm_fine=False)
+        loc0 = self.xrm.make_sure_var_in_reg(op.getarg(0))
         loc1 = self.rm.force_allocate_reg(op.result)
         self.Perform(op, [loc0], loc1)
         self.xrm.possibly_free_var(op.getarg(0))
         # ^^^ we force loc_newvalue in a reg (unless it's a Const),
         # because it will be needed anyway by the following setfield_gc.
         # It avoids loading it twice from the memory.
-        loc_base = self.rm.make_sure_var_in_reg(op.getarg(0), args,
-                                                imm_fine=False)
+        loc_base = self.rm.make_sure_var_in_reg(op.getarg(0), args)
         arglocs = [loc_base, loc_newvalue]
         # add eax, ecx and edx as extra "arguments" to ensure they are
         # saved and restored.  Fish in self.rm to know which of these

pypy/jit/backend/x86/regloc.py

 from pypy.rlib.unroll import unrolling_iterable
 from pypy.jit.backend.x86.arch import WORD, IS_X86_32, IS_X86_64
 from pypy.tool.sourcetools import func_with_new_name
-from pypy.rlib.objectmodel import specialize
+from pypy.rlib.objectmodel import specialize, instantiate
 from pypy.rlib.rarithmetic import intmask
 from pypy.jit.metainterp.history import FLOAT
 
                 return edx
         return eax
 
+    def add_offset(self, ofs):
+        result = instantiate(AddressLoc)
+        result._location_code = self._location_code
+        if self._location_code == 'm':
+            result.loc_m = (self.loc_m[0], self.loc_m[1] + ofs)
+        elif self._location_code == 'a':
+            result.loc_a = self.loc_a[:3] + (self.loc_a[3] + ofs,)
+        elif self._location_code == 'j':
+            result.value = self.value + ofs
+        else:
+            raise AssertionError(self._location_code)
+        return result
+
 class ConstFloatLoc(AssemblerLocation):
     # XXX: We have to use this class instead of just AddressLoc because
     # we want a width of 8  (... I think.  Check this!)
     def location_code(self):
         return 'j'
 
+if IS_X86_32:
+    class FloatImmedLoc(AssemblerLocation):
+        # This stands for an immediate float.  It cannot be directly used in
+        # any assembler instruction.  Instead, it is meant to be decomposed
+        # in two 32-bit halves.  On 64-bit, FloatImmedLoc() is a function
+        # instead; see below.
+        _immutable_ = True
+        width = 8
+
+        def __init__(self, floatvalue):
+            from pypy.rlib.longlong2float import float2longlong
+            self.aslonglong = float2longlong(floatvalue)
+
+        def low_part(self):
+            return intmask(self.aslonglong)
+
+        def high_part(self):
+            return intmask(self.aslonglong >> 32)
+
+        def low_part_loc(self):
+            return ImmedLoc(self.low_part())
+
+        def high_part_loc(self):
+            return ImmedLoc(self.high_part())
+
+        def __repr__(self):
+            from pypy.rlib.longlong2float import longlong2float
+            floatvalue = longlong2float(self.aslonglong)
+            return '<FloatImmedLoc(%s)>' % (floatvalue,)
+
+        def location_code(self):
+            raise NotImplementedError
+
+if IS_X86_64:
+    def FloatImmedLoc(floatvalue):
+        from pypy.rlib.longlong2float import float2longlong
+        value = intmask(float2longlong(floatvalue))
+        return ImmedLoc(value)
+
+
 REGLOCS = [RegLoc(i, is_xmm=False) for i in range(16)]
 XMMREGLOCS = [RegLoc(i, is_xmm=True) for i in range(16)]
 eax, ecx, edx, ebx, esp, ebp, esi, edi, r8, r9, r10, r11, r12, r13, r14, r15 = REGLOCS

pypy/jit/backend/x86/rx86.py

     CDQ = insn(rex_nw, '\x99')
 
     TEST8_mi = insn(rex_w, '\xF6', orbyte(0<<3), mem_reg_plus_const(1), immediate(2, 'b'))
+    TEST8_ji = insn(rex_w, '\xF6', orbyte(0<<3), '\x05', immediate(1), immediate(2, 'b'))
     TEST_rr = insn(rex_w, '\x85', register(2,8), register(1), '\xC0')
 
     # x87 instructions

pypy/jit/backend/x86/test/test_rx86.py

     assert_encodes_as(CodeBuilder32, 'OR8_rr', (bl, bh), '\x08\xFB')
 
 def test_test8_mi():
-    assert_encodes_as(CodeBuilder32, 'TEST8_mi', ((edx, 16), 99), '\xF6\x42\x10\x63')
+    assert_encodes_as(CodeBuilder32, 'TEST8_mi', ((edx, 16), 99),
+                      '\xF6\x42\x10\x63')
+
+def test_test8_ji():
+    assert_encodes_as(CodeBuilder32, 'TEST8_ji', (0x12345678, 99),
+                      '\xF6\x05\x78\x56\x34\x12\x63')
 
 def test_mov8():
     cb = CodeBuilder32

pypy/jit/metainterp/optimizeopt/rewrite.py

 from pypy.jit.metainterp.resoperation import rop, ResOperation
 from pypy.jit.codewriter.effectinfo import EffectInfo
 from pypy.jit.metainterp.optimizeopt.intutils import IntBound
+from pypy.rlib.rarithmetic import highest_bit
+
 
 class OptRewrite(Optimization):
     """Rewrite operations into equivalent, cheaper operations.
              (v2.is_constant() and v2.box.getint() == 0):
             self.make_constant_int(op.result, 0)
         else:
+            for lhs, rhs in [(v1, v2), (v2, v1)]:
+                # x & (x -1) == 0 is a quick test for power of 2
+                if (lhs.is_constant() and
+                    (lhs.box.getint() & (lhs.box.getint() - 1)) == 0):
+                    new_rhs = ConstInt(highest_bit(lhs.box.getint()))
+                    op = op.copy_and_change(rop.INT_LSHIFT, args=[rhs.box, new_rhs])
+                    break
+
             self.emit_operation(op)
 
     def optimize_CALL_PURE(self, op):
         if v1.intbound.known_ge(IntBound(0, 0)) and v2.is_constant():
             val = v2.box.getint()
             if val & (val - 1) == 0 and val > 0: # val == 2**shift
-                shift = 0
-                while (1 << shift) < val:
-                    shift += 1
                 op = op.copy_and_change(rop.INT_RSHIFT,
-                                        args = [op.getarg(0), ConstInt(shift)])
+                                        args = [op.getarg(0), ConstInt(highest_bit(val))])
         self.emit_operation(op)
 
 

pypy/jit/metainterp/optimizeopt/unroll.py

 from pypy.jit.metainterp.history import make_hashable_int
 from pypy.jit.codewriter.effectinfo import EffectInfo
 
+# Assumptions
+# ===========
+#
+# For this to work some assumptions had to be made about the
+# optimizations performed. At least for the optimizations that are
+# allowed to operate across the loop boundaries. To enforce this, the
+# optimizer chain is recreated at the end of the preamble and only the
+# state of the optimizations that fulfill those assumptions are kept.
+# Since part of this state is stored in virtuals all OptValue objects
+# are also recreated to allow virtuals not supported to be forced.
+#
+# First of all, the optimizations are not allowed to introduce new
+# boxes. It is the unoptimized version of the trace that is inlined to 
+# form the second iteration of the loop. Otherwise the
+# state of the virtuals would not be updated correctly. Whenever some
+# box from the first iteration is reused in the second iteration, it
+# is added to the input arguments of the loop as well as to the
+# arguments of the jump at the end of the preamble. This means that
+# inlining the jump from the unoptimized trace will not work since it
+# contains too few arguments.  Instead the jump at the end of the
+# preamble is inlined. If the arguments of that jump contains boxes
+# that were produced by one of the optimizations, and thus never seen
+# by the inliner, the inliner will not be able to inline them. There
+# is no way of known what these boxes are supposed to contain in the
+# third iteration.
+#
+# The second assumption is that the state of the optimizer should be the
+# same after the second iteration as after the first. This have forced
+# us to disable store sinking across loop boundaries. Consider the
+# following trace
+#
+#         [p1, p2]
+#         i1 = getfield_gc(p1, descr=nextdescr)
+#         i2 = int_sub(i1, 1)
+#         i2b = int_is_true(i2)
+#         guard_true(i2b) []
+#         setfield_gc(p2, i2, descr=nextdescr)
+#         p3 = new_with_vtable(ConstClass(node_vtable))
+#         jump(p2, p3)
+#
+# At the start of the preamble, p1 and p2 will be pointers. The
+# setfield_gc will be removed by the store sinking heap optimizer, and
+# p3 will become a virtual. Jumping to the loop will make p1 a pointer
+# and p2 a virtual at the start of the loop. The setfield_gc will now
+# be absorbed into the virtual p2 and never seen by the heap
+# optimizer. At the end of the loop both p2 and p3 are virtuals, but
+# the loop needs p2 to be a pointer to be able to call itself. So it
+# is forced producing the operations 
+#
+#         p2 = new_with_vtable(ConstClass(node_vtable))
+#         setfield_gc(p2, i2, descr=nextdescr)
+#
+# In this case the setfield_gc is not store sinked, which means we are
+# not in the same state at the end of the loop as at the end of the
+# preamble. When we now call the loop again, the first 4 operations of
+# the trace were optimized under the wrong assumption that the
+# setfield_gc was store sinked which could lead to errors. In this
+# case what would happen is that it would be inserted once more in
+# front of the guard. 
+
+
+
 # FIXME: Introduce some VirtualOptimizer super class instead
 
 def optimize_unroll(metainterp_sd, loop, optimizations):

pypy/jit/metainterp/test/test_basic.py

         self.check_loop_count(1)
         self.check_loops({'guard_true': 1,
                           'int_add': 2, 'int_sub': 1, 'int_gt': 1,
-                          'int_mul': 1,
+                          'int_lshift': 1,
                           'jump': 1})
 
     def test_loop_invariant_mul_bridge1(self):

pypy/jit/metainterp/test/test_optimizeopt.py

         """
         self.optimize_loop(ops, expected)
 
+    def test_mul_to_lshift(self):
+        ops = """
+        [i1, i2]
+        i3 = int_mul(i1, 2)
+        i4 = int_mul(2, i2)
+        i5 = int_mul(i1, 32)
+        i6 = int_mul(i1, i2)
+        jump(i5, i6)
+        """
+        expected = """
+        [i1, i2]
+        i3 = int_lshift(i1, 1)
+        i4 = int_lshift(i2, 1)
+        i5 = int_lshift(i1, 5)
+        i6 = int_mul(i1, i2)
+        jump(i5, i6)
+        """
+        self.optimize_loop(ops, expected)
+
     def test_lshift_rshift(self):
         ops = """
         [i1, i2, i2b, i1b]

pypy/jit/metainterp/test/test_send.py

         # However, this doesn't match the initial value of 'w'.
         # XXX This not completely easy to check...
         self.check_loop_count(1)
-        self.check_loops(int_add=0, int_mul=1, guard_class=0,
+        self.check_loops(int_add=0, int_lshift=1, guard_class=0,
                          new_with_vtable=0, new=0)
 
     def test_indirect_call_unknown_object_1(self):

pypy/jit/tool/showstats.py

 
 def main(argv):
     log = logparser.parse_log_file(argv[0])
-    log_count_lines = open(argv[0] + '.count').readlines()
     parts = logparser.extract_category(log, "jit-log-opt-")
     for i, oplist in enumerate(parts):
         loop = parse(oplist, no_namespace=True, nonstrict=True)
             print "Loop #%d, length: %d, opcodes: %d, guards: %d" % (i, num_ops, num_dmp, num_guards)
         else:
             print "Loop #%d, length: %d, opcodes: %d, guards: %d, %f" % (i, num_ops, num_dmp, num_guards, num_ops/num_dmp)
-        print loop.comment, "run", log_count_lines[i].split(":")[1].strip(), "times"
         
 if __name__ == '__main__':
     main(sys.argv[1:])

pypy/module/pypyjit/policy.py

                 modname == '__builtin__.abstractinst' or
                 modname == '__builtin__.interp_classobj' or
                 modname == '__builtin__.functional' or
-                modname == '__builtin__.descriptor'):
+                modname == '__builtin__.descriptor' or
+                modname == 'thread.os_local'):
             return True
         if '.' in modname:
             modname, _ = modname.split('.', 1)

pypy/module/pypyjit/test/test_policy.py

     from pypy.module.__builtin__.descriptor import W_Property
     assert pypypolicy.look_inside_function(W_Property.get.im_func)
 
+def test_thread_local():
+    from pypy.module.thread.os_local import Local
+    assert pypypolicy.look_inside_function(Local.getdict.im_func)
+
 def test_pypy_module():
     from pypy.module._random.interp_random import W_Random
     assert not pypypolicy.look_inside_function(W_Random.random)

pypy/module/pypyjit/test/test_pypy_c.py

                          ([a3, b3], 2000 * res3),
                          count_debug_merge_point=False)
         
+    def test_mod(self):
+        py.test.skip('Results are correct, but traces 1902 times (on trunk too).')
+        avalues = ('a', 'b', 7, -42, 8)
+        bvalues = ['b'] + range(-10, 0) + range(1,10)
+        code = ''
+        a1, b1, res1 = 10, 20, 0
+        a2, b2, res2 = 10, -20, 0
+        a3, b3, res3 = -10, -20, 0
+        def dd(a, b, aval, bval):
+            m = {'a': aval, 'b': bval}
+            if not isinstance(a, int):
+                a=m[a]
+            if not isinstance(b, int):
+                b=m[b]
+            return a % b
+        for a in avalues:
+            for b in bvalues:
+                code += '                sa += %s %% %s\n' % (a, b)
+                res1 += dd(a, b, a1, b1)
+                res2 += dd(a, b, a2, b2)
+                res3 += dd(a, b, a3, b3)
+        self.run_source('''
+        def main(a, b):
+            i = sa = 0
+            while i < 2000:
+                if a > 0: pass
+                if 1 < b < 2: pass
+%s
+                i += 1
+            return sa
+        ''' % code, 0, ([a1, b1], 2000 * res1),
+                         ([a2, b2], 2000 * res2),
+                         ([a3, b3], 2000 * res3),
+                         count_debug_merge_point=False)
+        
 
 class AppTestJIT(PyPyCJITTests):
     def setup_class(cls):

pypy/module/thread/os_local.py

         except KeyError:
             # create a new dict for this thread
             space = self.space
-            w_dict = self.dicts[ident] = space.newdict()
+            w_dict = self.dicts[ident] = space.newdict(instance=True)
             # call __init__
             try:
                 w_self = space.wrap(self)

pypy/rlib/longlong2float.py

+"""
+This module exposes the functions longlong2float() and float2longlong(),
+which cast the bit pattern of a long long into a float and back.
+"""
+from pypy.rpython.lltypesystem import lltype, rffi
+
+
+# -------- implement longlong2float and float2longlong --------
+DOUBLE_ARRAY_PTR = lltype.Ptr(lltype.Array(rffi.DOUBLE))
+LONGLONG_ARRAY_PTR = lltype.Ptr(lltype.Array(rffi.LONGLONG))
+
+# these definitions are used only in tests, when not translated
+def longlong2float_emulator(llval):
+    d_array = lltype.malloc(DOUBLE_ARRAY_PTR.TO, 1, flavor='raw')
+    ll_array = rffi.cast(LONGLONG_ARRAY_PTR, d_array)
+    ll_array[0] = llval
+    floatval = d_array[0]
+    lltype.free(d_array, flavor='raw')
+    return floatval
+
+def float2longlong_emulator(floatval):
+    d_array = lltype.malloc(DOUBLE_ARRAY_PTR.TO, 1, flavor='raw')
+    ll_array = rffi.cast(LONGLONG_ARRAY_PTR, d_array)
+    d_array[0] = floatval
+    llval = ll_array[0]
+    lltype.free(d_array, flavor='raw')
+    return llval
+
+from pypy.translator.tool.cbuild import ExternalCompilationInfo
+eci = ExternalCompilationInfo(post_include_bits=["""
+static double pypy__longlong2float(long long x) {
+    return *((double*)&x);
+}
+static long long pypy__float2longlong(double x) {
+    return *((long long*)&x);
+}
+"""])
+
+longlong2float = rffi.llexternal(
+    "pypy__longlong2float", [rffi.LONGLONG], rffi.DOUBLE,
+    _callable=longlong2float_emulator, compilation_info=eci,
+    _nowrapper=True, pure_function=True)
+
+float2longlong = rffi.llexternal(
+    "pypy__float2longlong", [rffi.DOUBLE], rffi.LONGLONG,
+    _callable=float2longlong_emulator, compilation_info=eci,
+    _nowrapper=True, pure_function=True)

pypy/rlib/rarithmetic.py

         assert t.BITS <= r_longlong.BITS
         return build_int(None, t.SIGNED, r_longlong.BITS)
 
+def highest_bit(n):
+    """
+    Calculates the highest set bit in n.  This function assumes that n is a
+    power of 2 (and thus only has a single set bit).
+    """
+    assert n and (n & (n - 1)) == 0
+    i = -1
+    while n:
+        i += 1
+        n >>= 1
+    return i
+
 class base_int(long):
     """ fake unsigned integer implementation """
 

pypy/rlib/rbigint.py

         else:
             result = _x_sub(other, self)
         result.sign *= other.sign
-        result._normalize()
         return result
 
     def sub(self, other):
         while i > 1 and self.digits[i - 1] == 0:
             i -= 1
         assert i >= 1
-        self.digits = self.digits[:i]
+        if i != self._numdigits():
+            self.digits = self.digits[:i]
         if self._numdigits() == 1 and self.digits[0] == 0:
             self.sign = 0
 

pypy/rlib/test/test_rarithmetic.py

 def test_int_real_union():
     from pypy.rpython.lltypesystem.rffi import r_int_real
     assert compute_restype(r_int_real, r_int_real) is r_int_real
+
+def test_highest_bit():
+    py.test.raises(AssertionError, highest_bit, 0)
+    py.test.raises(AssertionError, highest_bit, 14)
+
+    for i in xrange(31):
+        assert highest_bit(2**i) == i

pypy/rpython/rint.py

             # return r + y*(((x^y)<0)&(r!=0));
             v_xor = hop.genop(prefix + 'xor', vlist,
                             resulttype=repr)
-            v_xor_le = hop.genop(prefix + 'le', [v_xor, c_zero],
+            v_xor_le = hop.genop(prefix + 'lt', [v_xor, c_zero],
                                resulttype=Bool)
             v_xor_le = hop.llops.convertvar(v_xor_le, bool_repr, repr)
             v_mod_ne = hop.genop(prefix + 'ne', [v_res, c_zero],
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.