[pypy-svn] r68993 - in pypy/branch/msvc-asmgcroot/pypy/translator/c: . gcc gcc/test gcc/test/msvc src

afa at codespeak.net afa at codespeak.net
Thu Nov 5 18:06:16 CET 2009


Author: afa
Date: Thu Nov  5 18:06:15 2009
New Revision: 68993

Modified:
   pypy/branch/msvc-asmgcroot/pypy/translator/c/gcc/test/msvc/track0.s
   pypy/branch/msvc-asmgcroot/pypy/translator/c/gcc/test/msvc/track8.s
   pypy/branch/msvc-asmgcroot/pypy/translator/c/gcc/test/msvc/track_switch0.s
   pypy/branch/msvc-asmgcroot/pypy/translator/c/gcc/test/test_asmgcroot.py
   pypy/branch/msvc-asmgcroot/pypy/translator/c/gcc/test/test_trackgcroot.py
   pypy/branch/msvc-asmgcroot/pypy/translator/c/gcc/trackgcroot.py
   pypy/branch/msvc-asmgcroot/pypy/translator/c/genc.py
   pypy/branch/msvc-asmgcroot/pypy/translator/c/src/mem.h
Log:
Shave the tragcroot yack until it produces a working pypy-c-jit with the Microsoft compiler.
It now works with optimizations enabled, which is good.

I changed the gcroot marker: there seems to be no way to 
prevent the optimizer from reusing the old value, unless we use 
some memory input outside the current stack, e.g a global variable.
Unfortunately this produces two operations, that we have to match
to remove the global variable access.

Also take care of some of the many inventive constructs generated by the optimizer.


Modified: pypy/branch/msvc-asmgcroot/pypy/translator/c/gcc/test/msvc/track0.s
==============================================================================
--- pypy/branch/msvc-asmgcroot/pypy/translator/c/gcc/test/msvc/track0.s	(original)
+++ pypy/branch/msvc-asmgcroot/pypy/translator/c/gcc/test/msvc/track0.s	Thu Nov  5 18:06:15 2009
@@ -117,7 +117,8 @@
 
 ; 1487 : 	l_v406 = pypy_asm_gcroot(l_v405);
 
-	test	DWORD PTR _l_v405$[esp+24], 0
+	mov	eax, DWORD PTR ?_constant_always_one_@?1??pypy_asm_gcroot@@9 at 9
+	imul	eax, DWORD PTR _l_v405$[esp+24]
 
 ; 1488 : 	l_items_2 = l_v406; /* for moving GCs */
 ; 1489 : 	l_v408 = RPyField((&pypy_g_ExcData), ed_exc_type);

Modified: pypy/branch/msvc-asmgcroot/pypy/translator/c/gcc/test/msvc/track8.s
==============================================================================
--- pypy/branch/msvc-asmgcroot/pypy/translator/c/gcc/test/msvc/track8.s	(original)
+++ pypy/branch/msvc-asmgcroot/pypy/translator/c/gcc/test/msvc/track8.s	Thu Nov  5 18:06:15 2009
@@ -212,7 +212,8 @@
 
 ; 1096 : 	l_v354 = pypy_asm_gcroot(l_v353);
 
-	test	DWORD PTR _l_v353$[esp+24], 0
+	mov	eax, DWORD PTR ?_constant_always_one_@?1??pypy_asm_gcroot@@9 at 9
+	imul	eax, DWORD PTR _l_v353$[esp+24]
 
 ; 1097 : 	l_a2_1 = l_v354; /* for moving GCs */
 ; 1098 : 	l_v356 = (void*)l_a5_1;
@@ -222,7 +223,8 @@
 
 ; 1099 : 	l_v357 = pypy_asm_gcroot(l_v356);
 
-	test	DWORD PTR _l_v356$[esp+24], 0
+	mov	eax, DWORD PTR ?_constant_always_one_@?1??pypy_asm_gcroot@@9 at 9
+	imul	eax, DWORD PTR _l_v356$[esp+24]
 
 ; 1100 : 	l_a5_1 = l_v357; /* for moving GCs */
 ; 1101 : 	l_v359 = (void*)l_a6_1;
@@ -232,7 +234,8 @@
 
 ; 1102 : 	l_v360 = pypy_asm_gcroot(l_v359);
 
-	test	DWORD PTR _l_v359$[esp+24], 0
+	mov	eax, DWORD PTR ?_constant_always_one_@?1??pypy_asm_gcroot@@9 at 9
+	imul	eax, DWORD PTR _l_v359$[esp+24]
 
 ; 1103 : 	l_a6_1 = l_v360; /* for moving GCs */
 ; 1104 : 	l_v362 = (void*)l_a1_1;
@@ -241,7 +244,8 @@
 
 ; 1105 : 	l_v363 = pypy_asm_gcroot(l_v362);
 
-	test	DWORD PTR _l_v362$[esp+24], 0
+	mov	eax, DWORD PTR ?_constant_always_one_@?1??pypy_asm_gcroot@@9 at 9
+	imul	eax, DWORD PTR _l_v362$[esp+24]
 
 ; 1106 : 	l_a1_1 = l_v363; /* for moving GCs */
 ; 1107 : 	l_v365 = (void*)l_a3_1;
@@ -250,7 +254,8 @@
 
 ; 1108 : 	l_v366 = pypy_asm_gcroot(l_v365);
 
-	test	DWORD PTR _l_v365$[esp+24], 0
+	mov	eax, DWORD PTR ?_constant_always_one_@?1??pypy_asm_gcroot@@9 at 9
+	imul	eax, DWORD PTR _l_v365$[esp+24]
 
 ; 1109 : 	l_a3_1 = l_v366; /* for moving GCs */
 ; 1110 : 	l_v368 = (void*)l_a4_1;
@@ -260,7 +265,8 @@
 
 ; 1111 : 	l_v369 = pypy_asm_gcroot(l_v368);
 
-	test	DWORD PTR _l_v368$[esp+24], 0
+	mov	eax, DWORD PTR ?_constant_always_one_@?1??pypy_asm_gcroot@@9 at 9
+	imul	eax, DWORD PTR _l_v368$[esp+24]
 
 ; 1112 : 	l_a4_1 = l_v369; /* for moving GCs */
 ; 1113 : 	l_v335 = (struct pypy_src8_A0 *)l_v428;
@@ -302,7 +308,8 @@
 
 ; 1126 : 	l_v377 = pypy_asm_gcroot(l_v376);
 
-	test	DWORD PTR _l_v376$[esp+24], 0
+	mov	eax, DWORD PTR ?_constant_always_one_@?1??pypy_asm_gcroot@@9 at 9
+	imul	eax, DWORD PTR _l_v376$[esp+24]
 
 ; 1127 : 	l_a2_1 = l_v377; /* for moving GCs */
 ; 1128 : 	l_v379 = (void*)l_a6_1;
@@ -312,7 +319,8 @@
 
 ; 1129 : 	l_v380 = pypy_asm_gcroot(l_v379);
 
-	test	DWORD PTR _l_v379$[esp+24], 0
+	mov	eax, DWORD PTR ?_constant_always_one_@?1??pypy_asm_gcroot@@9 at 9
+	imul	eax, DWORD PTR _l_v379$[esp+24]
 
 ; 1130 : 	l_a6_1 = l_v380; /* for moving GCs */
 ; 1131 : 	l_v382 = (void*)l_a1_1;
@@ -321,7 +329,8 @@
 
 ; 1132 : 	l_v383 = pypy_asm_gcroot(l_v382);
 
-	test	DWORD PTR _l_v382$[esp+24], 0
+	mov	eax, DWORD PTR ?_constant_always_one_@?1??pypy_asm_gcroot@@9 at 9
+	imul	eax, DWORD PTR _l_v382$[esp+24]
 
 ; 1133 : 	l_a1_1 = l_v383; /* for moving GCs */
 ; 1134 : 	l_v385 = (void*)l_v335;
@@ -330,7 +339,8 @@
 
 ; 1135 : 	l_v386 = pypy_asm_gcroot(l_v385);
 
-	test	DWORD PTR _l_v385$[esp+24], 0
+	mov	eax, DWORD PTR ?_constant_always_one_@?1??pypy_asm_gcroot@@9 at 9
+	imul	eax, DWORD PTR _l_v385$[esp+24]
 
 ; 1136 : 	l_v335 = l_v386; /* for moving GCs */
 ; 1137 : 	l_v388 = (void*)l_a3_1;
@@ -339,7 +349,8 @@
 
 ; 1138 : 	l_v389 = pypy_asm_gcroot(l_v388);
 
-	test	DWORD PTR _l_v388$[esp+24], 0
+	mov	eax, DWORD PTR ?_constant_always_one_@?1??pypy_asm_gcroot@@9 at 9
+	imul	eax, DWORD PTR _l_v388$[esp+24]
 
 ; 1139 : 	l_a3_1 = l_v389; /* for moving GCs */
 ; 1140 : 	l_v391 = (void*)l_a5_1;
@@ -349,7 +360,8 @@
 
 ; 1141 : 	l_v392 = pypy_asm_gcroot(l_v391);
 
-	test	DWORD PTR _l_v391$[esp+24], 0
+	mov	eax, DWORD PTR ?_constant_always_one_@?1??pypy_asm_gcroot@@9 at 9
+	imul	eax, DWORD PTR _l_v391$[esp+24]
 
 ; 1142 : 	l_a5_1 = l_v392; /* for moving GCs */
 ; 1143 : 	l_v394 = (void*)l_a4_1;
@@ -359,7 +371,8 @@
 
 ; 1144 : 	l_v395 = pypy_asm_gcroot(l_v394);
 
-	test	DWORD PTR _l_v394$[esp+24], 0
+	mov	eax, DWORD PTR ?_constant_always_one_@?1??pypy_asm_gcroot@@9 at 9
+	imul	eax, DWORD PTR _l_v394$[esp+24]
 
 ; 1145 : 	l_a4_1 = l_v395; /* for moving GCs */
 ; 1146 : 	l_v397 = RPyField((&pypy_g_ExcData), ed_exc_type);
@@ -398,7 +411,8 @@
 
 ; 1157 : 	l_v402 = pypy_asm_gcroot(l_v401);
 
-	test	DWORD PTR _l_v401$[esp+24], 0
+	mov	eax, DWORD PTR ?_constant_always_one_@?1??pypy_asm_gcroot@@9 at 9
+	imul	eax, DWORD PTR _l_v401$[esp+24]
 
 ; 1158 : 	l_a2_1 = l_v402; /* for moving GCs */
 ; 1159 : 	l_v404 = (void*)l_a1_1;
@@ -407,7 +421,8 @@
 
 ; 1160 : 	l_v405 = pypy_asm_gcroot(l_v404);
 
-	test	DWORD PTR _l_v404$[esp+24], 0
+	mov	eax, DWORD PTR ?_constant_always_one_@?1??pypy_asm_gcroot@@9 at 9
+	imul	eax, DWORD PTR _l_v404$[esp+24]
 
 ; 1161 : 	l_a1_1 = l_v405; /* for moving GCs */
 ; 1162 : 	l_v407 = (void*)l_a3_1;
@@ -416,7 +431,8 @@
 
 ; 1163 : 	l_v408 = pypy_asm_gcroot(l_v407);
 
-	test	DWORD PTR _l_v407$[esp+24], 0
+	mov	eax, DWORD PTR ?_constant_always_one_@?1??pypy_asm_gcroot@@9 at 9
+	imul	eax, DWORD PTR _l_v407$[esp+24]
 
 ; 1164 : 	l_a3_1 = l_v408; /* for moving GCs */
 ; 1165 : 	l_v410 = (void*)l_a6_1;
@@ -426,7 +442,8 @@
 
 ; 1166 : 	l_v411 = pypy_asm_gcroot(l_v410);
 
-	test	DWORD PTR _l_v410$[esp+24], 0
+	mov	eax, DWORD PTR ?_constant_always_one_@?1??pypy_asm_gcroot@@9 at 9
+	imul	eax, DWORD PTR _l_v410$[esp+24]
 
 ; 1167 : 	l_a6_1 = l_v411; /* for moving GCs */
 ; 1168 : 	l_v413 = (void*)l_a5_1;
@@ -436,7 +453,8 @@
 
 ; 1169 : 	l_v414 = pypy_asm_gcroot(l_v413);
 
-	test	DWORD PTR _l_v413$[esp+24], 0
+	mov	eax, DWORD PTR ?_constant_always_one_@?1??pypy_asm_gcroot@@9 at 9
+	imul	eax, DWORD PTR _l_v413$[esp+24]
 
 ; 1170 : 	l_a5_1 = l_v414; /* for moving GCs */
 ; 1171 : 	l_v416 = (void*)l_a4_1;
@@ -446,7 +464,8 @@
 
 ; 1172 : 	l_v417 = pypy_asm_gcroot(l_v416);
 
-	test	DWORD PTR _l_v416$[esp+24], 0
+	mov	eax, DWORD PTR ?_constant_always_one_@?1??pypy_asm_gcroot@@9 at 9
+	imul	eax, DWORD PTR _l_v416$[esp+24]
 
 ; 1173 : 	l_a4_1 = l_v417; /* for moving GCs */
 ; 1174 : 	l_v419 = RPyField((&pypy_g_ExcData), ed_exc_type);

Modified: pypy/branch/msvc-asmgcroot/pypy/translator/c/gcc/test/msvc/track_switch0.s
==============================================================================
--- pypy/branch/msvc-asmgcroot/pypy/translator/c/gcc/test/msvc/track_switch0.s	(original)
+++ pypy/branch/msvc-asmgcroot/pypy/translator/c/gcc/test/msvc/track_switch0.s	Thu Nov  5 18:06:15 2009
@@ -131,7 +131,8 @@
 
 ; 15663: 	l_v271559 = pypy_asm_gcroot(l_v271558);
 
-	test	DWORD PTR _l_v271558$[ebp], 0
+	mov	eax, DWORD PTR ?_constant_always_one_@?1??pypy_asm_gcroot@@9 at 9
+	imul	eax, DWORD PTR _l_v271558$[ebp]
 	mov	edx, DWORD PTR _l_v271558$[ebp]
 	mov	DWORD PTR _l_v271559$[ebp], edx
 

Modified: pypy/branch/msvc-asmgcroot/pypy/translator/c/gcc/test/test_asmgcroot.py
==============================================================================
--- pypy/branch/msvc-asmgcroot/pypy/translator/c/gcc/test/test_asmgcroot.py	(original)
+++ pypy/branch/msvc-asmgcroot/pypy/translator/c/gcc/test/test_asmgcroot.py	Thu Nov  5 18:06:15 2009
@@ -154,13 +154,6 @@
         res = self.run('callback_simple')
         assert res == 4900
 
-    if sys.platform == 'win32':
-        def test_callback_with_collect(self):
-            py.test.skip("No libffi yet with mingw32")
-
-        def define_callback_with_collect(cls):
-            return lambda: 0
-
 
 class TestAsmGCRootWithSemiSpaceGC_Mingw32(TestAsmGCRootWithSemiSpaceGC):
     # for the individual tests see
@@ -181,3 +174,10 @@
         config = TestAsmGCRootWithSemiSpaceGC.make_config()
         config.translation.cc = 'mingw32'
         return config
+
+
+    def test_callback_with_collect(self):
+        py.test.skip("No libffi yet with mingw32")
+
+    def define_callback_with_collect(cls):
+        return lambda: 0

Modified: pypy/branch/msvc-asmgcroot/pypy/translator/c/gcc/test/test_trackgcroot.py
==============================================================================
--- pypy/branch/msvc-asmgcroot/pypy/translator/c/gcc/test/test_trackgcroot.py	(original)
+++ pypy/branch/msvc-asmgcroot/pypy/translator/c/gcc/test/test_trackgcroot.py	Thu Nov  5 18:06:15 2009
@@ -122,7 +122,8 @@
         yield check_computegcmaptable, format, path
 
 
-r_expected = re.compile(r"\s*;;\s*expected\s+([{].+[}])")
+r_expected        = re.compile(r"\s*;;\s*expected\s+([{].+[}])")
+r_gcroot_constant = re.compile(r";\tmov\t.+, .+_constant_always_one_")
 
 def check_computegcmaptable(format, path):
     if format == 'msvc':
@@ -159,6 +160,11 @@
             else:
                 expectedlines.insert(i-2, '\t.globl\t%s\n' % (label,))
                 expectedlines.insert(i-1, '%s=.+%d\n' % (label, OFFSET_LABELS))
+        if format == 'msvc' and r_gcroot_constant.match(line):
+            expectedlines[i] = ';' + expectedlines[i]
+            expectedlines[i+1] = (expectedlines[i+1]
+                                  .replace('\timul\t', '\tmov\t')
+                                  + '\t; GCROOT\n')
         prevline = line
     assert len(seen) == len(tabledict), (
         "computed table contains unexpected entries:\n%r" %

Modified: pypy/branch/msvc-asmgcroot/pypy/translator/c/gcc/trackgcroot.py
==============================================================================
--- pypy/branch/msvc-asmgcroot/pypy/translator/c/gcc/trackgcroot.py	(original)
+++ pypy/branch/msvc-asmgcroot/pypy/translator/c/gcc/trackgcroot.py	Thu Nov  5 18:06:15 2009
@@ -1,47 +1,36 @@
 #! /usr/bin/env python
 import autopath
-
 import re, sys, os, random
 
-from pypy.translator.c.gcc.instruction import *
-
-LABEL               = r'([a-zA-Z_$.][a-zA-Z0-9_$@.]*)'
-
-# darwin
-r_textstart            = re.compile(r"\t.text\s*$")
-# see
-# http://developer.apple.com/documentation/developertools/Reference/Assembler/040-Assembler_Directives/asm_directives.html
-OTHERSECTIONS = ['section', 'zerofill',
-                 'const', 'static_const', 'cstring',
-                 'literal4', 'literal8', 'literal16',
-                 'constructor', 'desctructor',
-                 'symbol_stub',
-                 'data', 'static_data',
-                 'non_lazy_symbol_pointer', 'lazy_symbol_pointer',
-                 'dyld', 'mod_init_func', 'mod_term_func',
-                 'const_data'
-                 ]
-r_sectionstart         = re.compile(r"\t\.("+'|'.join(OTHERSECTIONS)+").*$")
+from pypy.translator.c.gcc.instruction import Insn, Label, InsnCall, InsnRet
+from pypy.translator.c.gcc.instruction import InsnFunctionStart, InsnStop
+from pypy.translator.c.gcc.instruction import InsnSetLocal, InsnCopyLocal
+from pypy.translator.c.gcc.instruction import InsnPrologue, InsnEpilogue
+from pypy.translator.c.gcc.instruction import InsnGCROOT
+from pypy.translator.c.gcc.instruction import InsnStackAdjust
+from pypy.translator.c.gcc.instruction import InsnCannotFollowEsp
+from pypy.translator.c.gcc.instruction import LocalVar, somenewvalue, frameloc
+from pypy.translator.c.gcc.instruction import LOC_REG, LOC_NOWHERE, LOC_MASK
+from pypy.translator.c.gcc.instruction import LOC_EBP_BASED, LOC_ESP_BASED
 
 OFFSET_LABELS   = 2**30
 
-# inside functions
-r_label         = re.compile(LABEL+"[:]\s*$")
-r_globl         = re.compile(r"\t[.]globl\t"+LABEL+"\s*$")
-r_globllabel    = re.compile(LABEL+r"=[.][+]%d\s*$"%OFFSET_LABELS)
-r_insn          = re.compile(r"\t([a-z]\w*)\s")
-r_jmp_switch    = re.compile(r"\tjmp\t[*]"+LABEL+"[(]")
-r_jmp_source    = re.compile(r"\d*[(](%[\w]+)[,)]")
-
 class FunctionGcRootTracker(object):
     skip = 0
 
     @classmethod
     def init_regexp(cls):
+        cls.r_label         = re.compile(cls.LABEL+"[:]\s*$")
+        cls.r_globl         = re.compile(r"\t[.]globl\t"+cls.LABEL+"\s*$")
+        cls.r_globllabel    = re.compile(cls.LABEL+r"=[.][+]%d\s*$"%OFFSET_LABELS)
+
+        cls.r_insn          = re.compile(r"\t([a-z]\w*)\s")
         cls.r_unaryinsn     = re.compile(r"\t[a-z]\w*\s+("+cls.OPERAND+")\s*$")
         cls.r_binaryinsn    = re.compile(r"\t[a-z]\w*\s+(?P<source>"+cls.OPERAND+"),\s*(?P<target>"+cls.OPERAND+")\s*$")
 
         cls.r_jump          = re.compile(r"\tj\w+\s+"+cls.LABEL+"\s*$")
+        cls.r_jmp_switch    = re.compile(r"\tjmp\t[*]"+cls.LABEL+"[(]")
+        cls.r_jmp_source    = re.compile(r"\d*[(](%[\w]+)[,)]")
 
     def __init__(self, funcname, lines, filetag=0):
         self.funcname = funcname
@@ -116,7 +105,7 @@
     def findlabels(self):
         self.labels = {}      # {name: Label()}
         for lineno, line in enumerate(self.lines):
-            match = r_label.match(line)
+            match = self.r_label.match(line)
             if match:
                 label = match.group(1)
                 assert label not in self.labels, "duplicate label"
@@ -142,7 +131,7 @@
                 continue
             self.currentlineno = lineno
             insn = []
-            match = r_insn.match(line)
+            match = self.r_insn.match(line)
 
             if self.r_bottom_marker.match(line):
                 self.is_stack_bottom = True
@@ -163,7 +152,7 @@
             elif line == '\t/* end_ignore_in_trackgcroot */\n':
                 ignore_insns = False
             else:
-                match = r_label.match(line)
+                match = self.r_label.match(line)
                 if match:
                     insn = self.labels[match.group(1)]
 
@@ -207,13 +196,15 @@
         for insn in self.insns:
             if isinstance(insn, (InsnRet, InsnEpilogue, InsnGCROOT)):
                 deltas = {}
+                if isinstance(insn, InsnRet):
+                    deltas[insn] = 0
                 self.walk_instructions_backwards(walker, insn, 0)
                 size_at_insn = []
                 for insn1, delta1 in deltas.items():
                     if hasattr(insn1, 'framesize'):
                         size_at_insn.append(insn1.framesize + delta1)
-                assert len(size_at_insn) > 0, (
-                    "cannot reach the start of the function??")
+                if not size_at_insn:
+                    continue
                 size_at_insn = size_at_insn[0]
                 for insn1, delta1 in deltas.items():
                     size_at_insn1 = size_at_insn - delta1
@@ -308,10 +299,10 @@
         # script); otherwise invent a name and add the label to tracker.lines.
         label = None
         # this checks for a ".globl NAME" followed by "NAME:"
-        match = r_globl.match(self.lines[call.lineno+1])
+        match = self.r_globl.match(self.lines[call.lineno+1])
         if match:
             label1 = match.group(1)
-            match = r_globllabel.match(self.lines[call.lineno+2])
+            match = self.r_globllabel.match(self.lines[call.lineno+2])
             if match:
                 label2 = match.group(1)
                 if label1 == label2:
@@ -525,7 +516,7 @@
 
     def visit_jmp(self, line):
         tablelabels = []
-        match = r_jmp_switch.match(line)
+        match = self.r_jmp_switch.match(line)
         if match:
             # this is a jmp *Label(%index), used for table-based switches.
             # Assume that the table is just a list of lines looking like
@@ -543,13 +534,13 @@
                     for s in insn.all_sources_of(loc):
                         # if the source looks like 8(%eax,%edx,4)
                         # %eax is the real source, %edx is an offset.
-                        match = r_jmp_source.match(s)
+                        match = self.r_jmp_source.match(s)
                         if match and not self.r_localvar_esp.match(s):
                             sources.append(match.group(1))
                         else:
                             sources.append(s)
                 for source in sources:
-                    label_match = re.compile(LABEL).match(source)
+                    label_match = re.compile(self.LABEL).match(source)
                     if label_match:
                         tablelabels.append(label_match.group(0))
                         return
@@ -589,7 +580,8 @@
         return InsnStop()
 
     def register_jump_to(self, label):
-        self.labels[label].previous_insns.append(self.insns[-1])
+        if not isinstance(self.insns[-1], InsnStop):
+            self.labels[label].previous_insns.append(self.insns[-1])
 
     def conditional_jump(self, line):
         match = self.r_jump.match(line)
@@ -652,14 +644,41 @@
         insns = [InsnCall(self.currentlineno),
                  InsnSetLocal(self.EAX)]      # the result is there
         if sys.platform == 'win32':
+            # On win32, the address of a foreign function must be
+            # computed, the optimizer may store it in a register.  We
+            # could ignore this, except when the function has a
+            # __stdcall calling convention...
+            def find_register(target):
+                reg = []
+                def walker(insn, locs):
+                    sources = []
+                    for loc in locs:
+                        for s in insn.all_sources_of(loc):
+                            sources.append(s)
+                    for source in sources:
+                        if re.match("DWORD PTR .+@", source):
+                            reg.append(source)
+                    if reg:
+                        return
+                    yield tuple(sources)
+                insn = InsnStop()
+                insn.previous_insns = [self.insns[-1]]
+                self.walk_instructions_backwards(walker, insn, (target,))
+                return reg
+
+            if match and self.r_localvarfp.match(target):
+                sources = find_register(target)
+                if sources:
+                    target, = sources
+
             # handle __stdcall calling convention:
             # Stack cleanup is performed by the called function,
             # Function name is decorated with "@N" where N is the stack size
-            if match and '@' in target:
+            if match and '@' in target and not target.startswith('@'):
                 insns.append(InsnStackAdjust(int(target.rsplit('@', 1)[1])))
-            # XXX some functions seem use the "fastcall" calling convention
-            # without their declaration, how can we guess the stack effect?
-            if match and target in ['__alldiv', '__allrem', '__allmul']:
+            # Some (intrinsic?) functions use the "fastcall" calling convention
+            # XXX without any declaration, how can we guess the stack effect?
+            if match and target in ['__alldiv', '__allrem', '__allmul', '__alldvrm']:
                 insns.append(InsnStackAdjust(16))
         return insns
 
@@ -734,12 +753,12 @@
     TOP_OF_STACK = 'DWORD PTR [esp]'
 
     OPERAND = r'(?:(:?WORD|DWORD|BYTE) PTR |OFFSET )?[_\w?:@$]*(?:[-+0-9]+)?(:?\[[-+*\w0-9]+\])?'
-    LABEL   = r'([a-zA-Z_$.][a-zA-Z0-9_$@.]*)'
+    LABEL   = r'([a-zA-Z_$@.][a-zA-Z0-9_$@.]*)'
 
     r_functionstart = re.compile(r"; Function compile flags: ")
     r_codestart     = re.compile(LABEL+r"\s+PROC\s*(:?;.+)?\n$")
     r_functionend   = re.compile(LABEL+r"\s+ENDP\s*$")
-    r_symboldefine =  re.compile(r"([_a-z0-9]+\$) = ([-0-9]+)\s*;.+\n")
+    r_symboldefine =  re.compile(r"([_A-Za-z0-9$]+) = ([-0-9]+)\s*;.+\n")
 
     LOCALVAR        = r"eax|edx|ecx|ebx|esi|edi|ebp|DWORD PTR [-+]?\d*\[esp[-+]?\d*\]"
     LOCALVARFP      = LOCALVAR + r"|DWORD PTR -?\d*\[ebp\]"
@@ -748,7 +767,8 @@
     r_localvar_esp  = re.compile(r"DWORD PTR ([-+]?\d+)?\[esp([-+]?\d+)?\]")
     r_localvar_ebp  = re.compile(r"DWORD PTR ([-+]?\d+)?\[ebp([-+]?\d+)?\]")
 
-    r_gcroot_marker = re.compile(r";.+ = pypy_asm_gcroot\(")
+    r_gcroot_marker = re.compile(r"$1") # never matches
+    r_gcroot_marker_var = re.compile(r"DWORD PTR .+_constant_always_one_.+pypy_asm_gcroot")
     r_bottom_marker = re.compile(r"\tcall\t_pypy_asm_stack_bottom\s*")
 
     r_unaryinsn_star= re.compile(r"\t[a-z]\w*\s+DWORD PTR ("+OPERAND+")\s*$")
@@ -759,7 +779,7 @@
     def init_regexp(cls):
         super(MsvcFunctionGcRootTracker, cls).init_regexp()
         cls.r_binaryinsn    = re.compile(r"\t[a-z]\w*\s+(?P<target>"+cls.OPERAND+r"),\s*(?P<source>"+cls.OPERAND+r")\s*(?:;.+)?$")
-        cls.r_jump = re.compile(r"\tj\w+\s+(?:SHORT |DWORD PTR )?"+LABEL+"\s*$")
+        cls.r_jump = re.compile(r"\tj\w+\s+(?:SHORT |DWORD PTR )?"+cls.LABEL+"\s*$")
 
     def __init__(self, lines, filetag=0):
         self.defines = {}
@@ -792,6 +812,7 @@
         locals()['visit_' + name] = getattr(FunctionGcRootTracker,
                                             'visit_' + name + 'l')
 
+    visit_int = FunctionGcRootTracker.visit_nop
     visit_npad = FunctionGcRootTracker.visit_nop
     # probably not GC pointers
     visit_cdq  = FunctionGcRootTracker.visit_nop
@@ -802,12 +823,75 @@
         except ValueError:
             return None
 
-    def _visit_gcroot_marker(self, line):
-        assert self.lines[self.currentlineno + 1] == "\n"
-        assert self.lines[self.currentlineno + 2].startswith("\ttest\tDWORD PTR")
-        match = self.r_binaryinsn.match(self.lines[self.currentlineno + 2])
-        loc = match.group("target")
-        return InsnGCROOT(self.replace_symbols(loc))
+    def _visit_gcroot_marker(self, line=None):
+        # two possible patterns:
+        # 1. mov reg, DWORD PTR _always_one_
+        #    imul target, reg
+        # 2. mov reg, DWORD PTR _always_one_
+        #    imul reg, target
+        assert self.lines[self.currentlineno].startswith("\tmov\t")
+        mov = self.r_binaryinsn.match(self.lines[self.currentlineno])
+        assert re.match("DWORD PTR .+_always_one_", mov.group("source"))
+        reg = mov.group("target")
+
+        self.lines[self.currentlineno] = ";" + self.lines[self.currentlineno]
+
+        # the 'imul' must appear in the same block; the 'reg' must not
+        # appear in the instructions between
+        imul = None
+        lineno = self.currentlineno + 1
+        stop = False
+        while not stop:
+            line = self.lines[lineno]
+            if line == '\n':
+                stop = True
+            elif line.startswith("\tjmp\t"):
+                stop = True
+            elif self.r_gcroot_marker_var.search(line):
+                stop = True
+            elif line.startswith("\tmov\t%s," % (reg,)):
+                # mov reg, <arg>
+                stop = True
+            elif line.startswith("\txor\t%s, %s" % (reg, reg)):
+                # xor reg, reg
+                stop = True
+            elif line.startswith("\timul\t"):
+                imul = self.r_binaryinsn.match(line)
+                imul_arg1 = imul.group("target")
+                imul_arg2 = imul.group("source")
+                break
+            # the register may not appear in other instructions
+            elif reg in line:
+                assert False, (line, lineno)
+
+            lineno += 1
+        else:
+            # No imul, the returned value is not used in this function
+            return []
+
+        if reg == imul_arg2:
+            self.lines[lineno] = ";" + self.lines[lineno]
+            return InsnGCROOT(self.replace_symbols(imul_arg1))
+        else:
+            assert reg == imul_arg1
+            self.lines[lineno] = "\tmov\t%s, %s\n" % (imul_arg1, imul_arg2)
+            if imul_arg2.startswith('OFFSET '):
+                # ignore static global variables
+                pass
+            else:
+                self.lines[lineno] += "\t; GCROOT\n"
+
+            return []
+
+    def insns_for_copy(self, source, target):
+        if self.r_gcroot_marker_var.match(source):
+            return self._visit_gcroot_marker()
+        if self.lines[self.currentlineno].endswith("\t; GCROOT\n"):
+            insns = [InsnGCROOT(self.replace_symbols(source))]
+        else:
+            insns = []
+        return insns + super(MsvcFunctionGcRootTracker, self).insns_for_copy(source, target)
+
 
 MsvcFunctionGcRootTracker.init_regexp()
 
@@ -881,16 +965,32 @@
     format = "darwin"
     FunctionGcRootTracker = DarwinFunctionGcRootTracker
 
+    r_textstart = re.compile(r"\t.text\s*$")
+
+    # see
+    # http://developer.apple.com/documentation/developertools/Reference/Assembler/040-Assembler_Directives/asm_directives.html
+    OTHERSECTIONS = ['section', 'zerofill',
+                     'const', 'static_const', 'cstring',
+                     'literal4', 'literal8', 'literal16',
+                     'constructor', 'desctructor',
+                     'symbol_stub',
+                     'data', 'static_data',
+                     'non_lazy_symbol_pointer', 'lazy_symbol_pointer',
+                     'dyld', 'mod_init_func', 'mod_term_func',
+                     'const_data'
+                     ]
+    r_sectionstart = re.compile(r"\t\.("+'|'.join(OTHERSECTIONS)+").*$")
+
     @classmethod
     def find_functions(cls, iterlines):
         functionlines = []
         in_text = False
         in_function = False
         for n, line in enumerate(iterlines):
-            if r_textstart.match(line):
+            if cls.r_textstart.match(line):
                 assert not in_text, "unexpected repeated .text start: %d" % n
                 in_text = True
-            elif r_sectionstart.match(line):
+            elif cls.r_sectionstart.match(line):
                 if in_function:
                     yield in_function, functionlines
                     functionlines = []
@@ -920,9 +1020,9 @@
         in_text = False
         in_function = False
         for n, line in enumerate(iterlines):
-            if r_textstart.match(line):
+            if cls.r_textstart.match(line):
                 in_text = True
-            elif r_sectionstart.match(line):
+            elif cls.r_sectionstart.match(line):
                 in_text = False
             elif in_text and cls.FunctionGcRootTracker.r_functionstart.match(line):
                 yield in_function, functionlines
@@ -966,18 +1066,27 @@
     def write_newfile(self, newfile, lines, grist):
         newlines = []
         for line in lines:
+            # truncate long comments
+            if line.startswith(";"):
+                line = line[:-1][:500] + '\n'
+
             # Workaround a bug in the .s files generated by msvc
-            # compiler: every float constant is exported with a name
-            # correcponding to its value, and will conflict with other
-            # modules.
-            line = line.replace('__real@',
-                                '__%s__real@' % grist)
+            # compiler: every string or float constant is exported
+            # with a name built after its value, and will conflict
+            # with other modules.
+            if line.startswith("PUBLIC\t__real@"):
+                line = '; ' + line
+            elif line.startswith("PUBLIC\t??_C@"):
+                line = '; ' + line
+
             # Because we insert labels in the code, some "SHORT" jumps
             # are now longer than 127 bytes.  We turn them all into
             # "NEAR" jumps.  Note that the assembler allocates space
             # for a near jump, but still generates a short jump when
             # it can.
             line = line.replace('\tjmp\tSHORT ', '\tjmp\t')
+            line = line.replace('\tjne\tSHORT ', '\tjne\t')
+            line = line.replace('\tje\tSHORT ',  '\tje\t')
 
             newlines.append(line)
 

Modified: pypy/branch/msvc-asmgcroot/pypy/translator/c/genc.py
==============================================================================
--- pypy/branch/msvc-asmgcroot/pypy/translator/c/genc.py	(original)
+++ pypy/branch/msvc-asmgcroot/pypy/translator/c/genc.py	Thu Nov  5 18:06:15 2009
@@ -486,9 +486,13 @@
             mk.rule(*rule)
 
         if self.config.translation.gcrootfinder == 'asmgcc':
-            sfiles = ['%s.s' % (cfile[:-2],) for cfile in mk.cfiles]
-            lblsfiles = ['%s.lbl.s' % (cfile[:-2],) for cfile in mk.cfiles]
-            gcmapfiles = ['%s.gcmap' % (cfile[:-2],) for cfile in mk.cfiles]
+            trackgcfiles = [cfile[:-2] for cfile in mk.cfiles]
+            if self.translator.platform.name == 'msvc':
+                trackgcfiles = [f for f in trackgcfiles
+                                if f.startswith(('implement', 'testing'))]
+            sfiles = ['%s.s' % (c,) for c in trackgcfiles]
+            lblsfiles = ['%s.lbl.s' % (c,) for c in trackgcfiles]
+            gcmapfiles = ['%s.gcmap' % (c,) for c in trackgcfiles]
             mk.definition('ASMFILES', sfiles)
             mk.definition('ASMLBLFILES', lblsfiles)
             mk.definition('GCMAPFILES', gcmapfiles)
@@ -500,11 +504,20 @@
                 python = ''
 
             if self.translator.platform.name == 'msvc':
-                lblofiles = ['%s.lbl.obj' % (cfile[:-2],) for cfile in mk.cfiles]
+                lblofiles = []
+                for cfile in mk.cfiles:
+                    f = cfile[:-2]
+                    if f in trackgcfiles:
+                        ofile = '%s.lbl.obj' % (f,)
+                    else:
+                        ofile = '%s.obj' % (f,)
+
+                    lblofiles.append(ofile)
                 mk.definition('ASMLBLOBJFILES', lblofiles)
                 mk.definition('OBJECTS', 'gcmaptable.obj $(ASMLBLOBJFILES)')
-                # almost all optimizations implied by /O2, except /Og
-                mk.definition('ASM_CFLAGS', '$(CFLAGS) /Od /Oi /Ot /Oy /Ob2 /GF /Gy')
+                # /Oi (enable intrinsics) and /Ob1 (some inlining) are mandatory
+                # even in debug builds
+                mk.definition('ASM_CFLAGS', '$(CFLAGS) /Od /Oi /Ob1')
                 mk.rule('.SUFFIXES', '.s', [])
                 mk.rule('.s.obj', '',
                         'cmd /c $(MASM) /nologo /Cx /Cp /Zm /coff /Fo$@ /c $< $(INCLUDEDIRS)')

Modified: pypy/branch/msvc-asmgcroot/pypy/translator/c/src/mem.h
==============================================================================
--- pypy/branch/msvc-asmgcroot/pypy/translator/c/src/mem.h	(original)
+++ pypy/branch/msvc-asmgcroot/pypy/translator/c/src/mem.h	Thu Nov  5 18:06:15 2009
@@ -17,16 +17,18 @@
    could make two copies of the local variable (e.g. one in the stack
    and one in a register), pass one to GCROOT, and later use the other
    one.  In practice the pypy_asm_gcroot() is often a no-op in the final
-   machine code and doesn't prevent most optimizations.  Getting the
-   asm() right was tricky, though.  The asm() is not volatile so that
-   gcc is free to delete it if the output variable is not used at all.
-   We need to prevent gcc from moving the asm() *before* the call that
-   could cause a collection; this is the purpose of the (unused)
-   __gcnoreorderhack input argument.  Any memory input argument would
-   have this effect: as far as gcc knows the call instruction can modify
-   arbitrary memory, thus creating the order dependency that we want. */
+   machine code and doesn't prevent most optimizations. */
 #ifndef _MSC_VER
 
+/* With gcc, getting the asm() right was tricky, though.  The asm() is
+   not volatile so that gcc is free to delete it if the output variable
+   is not used at all.  We need to prevent gcc from moving the asm()
+   *before* the call that could cause a collection; this is the purpose
+   of the (unused) __gcnoreorderhack input argument.  Any memory input
+   argument would have this effect: as far as gcc knows the call
+   instruction can modify arbitrary memory, thus creating the order
+   dependency that we want. */
+
 #define pypy_asm_gcroot(p) ({void*_r; \
                asm ("/* GCROOT %0 */" : "=g" (_r) : \
                     "0" (p), "m" (__gcnoreorderhack)); \
@@ -39,13 +41,23 @@
 #define pypy_asm_stack_bottom()  asm volatile ("/* GC_STACK_BOTTOM */" : : )
 
 #else
-/* Microsoft Compiler */
-static __forceinline
-void* pypy_asm_gcroot(void* _r1)
+
+/* With the msvc Microsoft Compiler, the optimizer seems free to move
+   any code (even asm) that involves local memory (registers and stack).
+   The _ReadWriteBarrier function has an effect only where the content
+   of a global variable is *really* used.  trackgcroot.py will remove
+   the extra instructions: the access to _constant_always_one_ is
+   removed, and the multiplication is replaced with a simple move. */
+
+static __forceinline void*
+pypy_asm_gcroot(void* _r1)
 {
-    __asm test _r1, 0
+	static volatile int _constant_always_one_ = 1;
+	(long)_r1 *= _constant_always_one_;
+	_ReadWriteBarrier();
     return _r1;
 }
+
 #define pypy_asm_keepalive(v)    __asm { }
 static __declspec(noinline) void pypy_asm_stack_bottom() { }
 



More information about the Pypy-commit mailing list