Commit 5ec6ea3e authored by tibbe's avatar tibbe Committed by Simon Marlow

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.
parent 5f48b24b
......@@ -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")
TOP=../../..
include $(TOP)/mk/boilerplate.mk
include $(TOP)/mk/test.mk
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, [''])
.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"
#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 ();
}
.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"
#include "Cmm.h"
// Small memcpies should unroll
callMemcpy (W_ dst, W_ src)
{
prim %memcpy(dst, src, 16, 4);
return ();
}
callMemcpy:
movq ; Move arguments into place
movq
movl
subq
movl
call memcpy
addq
jmp
#include "Cmm.h"
// Large memcpy's should lower to calls.
callMemcpy (W_ dst, W_ src)
{
prim %memcpy(dst, src, 1024, 4);
return ();
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment