Repository : ssh://darcs.haskell.org//srv/darcs/testsuite On branch : master
http://hackage.haskell.org/trac/ghc/changeset/a351a67a242f8484764fe450b973b2d4ac9d098e >--------------------------------------------------------------- commit a351a67a242f8484764fe450b973b2d4ac9d098e Author: Johan Tibell <johan.tib...@gmail.com> 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 (); +} _______________________________________________ Cvs-ghc mailing list Cvs-ghc@haskell.org http://www.haskell.org/mailman/listinfo/cvs-ghc