[commit: testsuite] master: Make it possible to test the generated assembly (a351a67)

Simon Marlow <[email protected]>
Newsgroups gmane.comp.lang.haskell.cvs.ghc
Message-ID <[email protected]>
Repository : ssh://darcs.haskell.org//srv/darcs/testsuite

On branch  : master

http://hackage.haskell.org/trac/ghc/changeset/a351a67a242f8484764fe450b973b2d4ac9d098e

>---------------------------------------------------------------

commit a351a67a242f8484764fe450b973b2d4ac9d098e
Author: Johan Tibell <[email protected]>
Date:   Tue May 31 11:56:58 2011 +0200

    Make it possible to test the generated assembly
    
    This test framework feature is inspired by a similar feature in LLVM.
    The programmer writes a bit of Cmm
    
        #include "Cmm.h"
    
        // Large memcpy's should lower to calls.
        callMemcpy
        {
          W_ dst, src;
          prim %memcpy(dst "ptr", src "ptr", 1024, 4) [];
        }
    
    and asserts what the generated assembly should look like, modulo
    register naming.
    
        callMemcpy:
        movq  ; Move arguments into place
        movq
        movl
        movl
        call memcpy
    
    Patch edited and updated by Simon Marlow, and I also added a test for
    unrolling memcpy and a simple constant-propagation test.

>---------------------------------------------------------------

 driver/testlib.py                                  |   54 +++++++++++++++++++-
 .../should_gen_asm}/Makefile                       |    0 
 tests/codeGen/should_gen_asm/all.T                 |    3 +
 .../should_gen_asm/memcpy-unroll-conprop.asm       |   21 ++++++++
 .../should_gen_asm/memcpy-unroll-conprop.cmm       |   14 +++++
 tests/codeGen/should_gen_asm/memcpy-unroll.asm     |   18 +++++++
 tests/codeGen/should_gen_asm/memcpy-unroll.cmm     |    8 +++
 tests/codeGen/should_gen_asm/memcpy.asm            |    9 +++
 tests/codeGen/should_gen_asm/memcpy.cmm            |    8 +++
 9 files changed, 134 insertions(+), 1 deletions(-)

diff --git a/driver/testlib.py b/driver/testlib.py
index 5853413..4531801 100644
--- a/driver/testlib.py
+++ b/driver/testlib.py
@@ -329,6 +329,12 @@ def if_arch( arch, f ):
     else:
         return normal
 
+def unless_arch( arch, f ):
+    if config.arch == arch:
+        return normal
+    else:
+        return f
+
 def if_wordsize( ws, f ):
     if config.wordsize == str(ws):
         return f
@@ -941,6 +947,33 @@ def do_compile( name, way, should_fail, top_mod, extra_mods, extra_hc_opts ):
     # no problems found, this test passed
     return passed()
 
+def compile_cmp_asm( name, way, extra_hc_opts ):
+    print 'Compile only, extra args = ', extra_hc_opts
+    pretest_cleanup(name)
+    result = simple_build( name + '.cmm', way, '-keep-s-files -O ' + extra_hc_opts, 0, '', 0, 0, 0)
+
+    if badResult(result):
+        return result
+
+    # the actual stderr should always match the expected, regardless
+    # of whether we expected the compilation to fail or not (successful
+    # compilations may generate warnings).
+
+    if getTestOpts().with_namebase == None:
+        namebase = name
+    else:
+        namebase = getTestOpts().with_namebase
+
+    (platform_specific, expected_asm_file) = platform_wordsize_qualify(namebase, 'asm')
+    actual_asm_file = qualify(name, 's')
+
+    if not compare_outputs('asm', two_normalisers(normalise_errmsg, normalise_asm), \
+                           expected_asm_file, actual_asm_file):
+        return failBecause('asm mismatch')
+
+    # no problems found, this test passed
+    return passed()
+
 # -----------------------------------------------------------------------------
 # Compile-and-run tests
 
@@ -1674,6 +1707,26 @@ def normalise_output( str ):
     str = re.sub('([^\\s])\\.exe', '\\1', str)
     return str
 
+def normalise_asm( str ):
+    lines = str.split('\n')
+    # Only keep instructions and labels not starting with a dot.
+    metadata = re.compile('^[ \t]*\\..*$')
+    out = []
+    for line in lines:
+      # Drop metadata directives (e.g. ".type")
+      if not metadata.match(line):
+        instr = line.lstrip().split()
+        # Drop empty lines.
+        if not instr:
+          continue
+        # Drop operands, except for call instructions.
+        elif instr[0] == 'call':
+          out.append(instr[0] + ' ' + instr[1])
+        else:
+          out.append(instr[0])
+    out = '\n'.join(out)
+    return out
+
 def if_verbose( n, str ):
     if config.verbose >= n:
         print str
@@ -2118,4 +2171,3 @@ def getStdout(cmd):
         return stdout
     else:
         raise Exception("Need subprocess to get stdout, but don't have it")
-
diff --git a/tests/annotations/should_compile/Makefile b/tests/codeGen/should_gen_asm/Makefile
similarity index 100%
copy from tests/annotations/should_compile/Makefile
copy to tests/codeGen/should_gen_asm/Makefile
diff --git a/tests/codeGen/should_gen_asm/all.T b/tests/codeGen/should_gen_asm/all.T
new file mode 100644
index 0000000..c262255
--- /dev/null
+++ b/tests/codeGen/should_gen_asm/all.T
@@ -0,0 +1,3 @@
+test('memcpy', unless_arch('x86_64',skip), compile_cmp_asm, [''])
+test('memcpy-unroll', unless_arch('x86_64',skip), compile_cmp_asm, [''])
+test('memcpy-unroll-conprop', unless_arch('x86_64',skip), compile_cmp_asm, [''])
diff --git a/tests/codeGen/should_gen_asm/memcpy-unroll-conprop.asm b/tests/codeGen/should_gen_asm/memcpy-unroll-conprop.asm
new file mode 100644
index 0000000..1bafb34
--- /dev/null
+++ b/tests/codeGen/should_gen_asm/memcpy-unroll-conprop.asm
@@ -0,0 +1,21 @@
+.text
+	.align 8
+.globl callMemcpy
+.type callMemcpy, @object
+callMemcpy:
+.Lc8:
+	testq %rbx,%rbx
+	je .Lcb
+	movl 0(%r14),%eax
+	movl %eax,0(%rbx)
+	movl 4(%r14),%eax
+	movl %eax,4(%rbx)
+	movl 8(%r14),%eax
+	movl %eax,8(%rbx)
+	movl 12(%r14),%eax
+	movl %eax,12(%rbx)
+.Lcb:
+	jmp *(%rbp)
+	.size callMemcpy, .-callMemcpy
+.section .note.GNU-stack,"",@progbits
+.ident "GHC 7.7.20121009"
diff --git a/tests/codeGen/should_gen_asm/memcpy-unroll-conprop.cmm b/tests/codeGen/should_gen_asm/memcpy-unroll-conprop.cmm
new file mode 100644
index 0000000..be4883d
--- /dev/null
+++ b/tests/codeGen/should_gen_asm/memcpy-unroll-conprop.cmm
@@ -0,0 +1,14 @@
+#include "Cmm.h"
+
+// Check that we propagate the constants into the branch
+callMemcpy (W_ dst, W_ src)
+{
+    W_ size;
+    W_ alig;
+    size = 16;
+    alig = 4;
+    if (dst != 0) {
+      prim %memcpy(dst, src, size, alig);
+    }
+    return ();
+}
diff --git a/tests/codeGen/should_gen_asm/memcpy-unroll.asm b/tests/codeGen/should_gen_asm/memcpy-unroll.asm
new file mode 100644
index 0000000..ffb27e7
--- /dev/null
+++ b/tests/codeGen/should_gen_asm/memcpy-unroll.asm
@@ -0,0 +1,18 @@
+.text
+	.align 8
+.globl callMemcpy
+.type callMemcpy, @object
+callMemcpy:
+.Lc3:
+	movl 0(%r14),%eax
+	movl %eax,0(%rbx)
+	movl 4(%r14),%eax
+	movl %eax,4(%rbx)
+	movl 8(%r14),%eax
+	movl %eax,8(%rbx)
+	movl 12(%r14),%eax
+	movl %eax,12(%rbx)
+	jmp *(%rbp)
+	.size callMemcpy, .-callMemcpy
+.section .note.GNU-stack,"",@progbits
+.ident "GHC 7.7.20121009"
diff --git a/tests/codeGen/should_gen_asm/memcpy-unroll.cmm b/tests/codeGen/should_gen_asm/memcpy-unroll.cmm
new file mode 100644
index 0000000..95656b4
--- /dev/null
+++ b/tests/codeGen/should_gen_asm/memcpy-unroll.cmm
@@ -0,0 +1,8 @@
+#include "Cmm.h"
+
+// Small memcpies should unroll
+callMemcpy (W_ dst, W_ src)
+{
+  prim %memcpy(dst, src, 16, 4);
+  return ();
+}
diff --git a/tests/codeGen/should_gen_asm/memcpy.asm b/tests/codeGen/should_gen_asm/memcpy.asm
new file mode 100644
index 0000000..1fb604f
--- /dev/null
+++ b/tests/codeGen/should_gen_asm/memcpy.asm
@@ -0,0 +1,9 @@
+callMemcpy:
+        movq  ; Move arguments into place
+        movq
+        movl
+        subq
+        movl
+        call memcpy
+        addq
+        jmp
diff --git a/tests/codeGen/should_gen_asm/memcpy.cmm b/tests/codeGen/should_gen_asm/memcpy.cmm
new file mode 100644
index 0000000..0ff1663
--- /dev/null
+++ b/tests/codeGen/should_gen_asm/memcpy.cmm
@@ -0,0 +1,8 @@
+#include "Cmm.h"
+
+// Large memcpy's should lower to calls.
+callMemcpy (W_ dst, W_ src)
+{
+  prim %memcpy(dst, src, 1024, 4);
+  return ();
+}
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.