Add dg test for matching function bodies
authorRichard Sandiford <richard.sandiford@arm.com>
Mon, 29 Jul 2019 08:46:46 +0000 (08:46 +0000)
committerRichard Sandiford <rsandifo@gcc.gnu.org>
Mon, 29 Jul 2019 08:46:46 +0000 (08:46 +0000)
There isn't a 1:1 mapping from SVE intrinsics to SVE instructions,
but the intrinsics are still close enough to the instructions for
there to be a specific preferred sequence (or sometimes choice of
preferred sequences) for a given combination of operands.  Sometimes
these sequences will be one instruction, sometimes they'll be several.

I therefore wanted a convenient way of matching the exact assembly
implementation of a given function.  It's possible to do that using
single scan-assembler lines, but:

(a) they become hard to read for multiline matches
(b) the PASS/FAIL lines tend to be overly long
(c) it's useful to have a single place that skips over uninteresting
    lines, such as entry block labels and .cfi_* directives, without
    being overly broad

This patch therefore adds a new check-function-bodies dg-final test
that looks for specially-formatted comments.  As a demo, the patch
converts the SVE vec_init tests to use the new harness instead of
scan-assembler.

The regexps in parse_function_bodies are fairly general, but might
still need to be extended in future for targets like Darwin or AIX.

2019-07-29  Richard Sandiford  <richard.sandiford@arm.com>

gcc/
* doc/sourcebuild.texi (check-function-bodies): Document.

gcc/testsuite/
* lib/scanasm.exp (parse_function_bodies, check_function_body)
(check-function-bodies): New procedures.
* gcc.target/aarch64/sve/init_1.c: Use check-function-bodies
instead of scan-assembler.
* gcc.target/aarch64/sve/init_2.c: Likewise.
* gcc.target/aarch64/sve/init_3.c: Likewise.
* gcc.target/aarch64/sve/init_4.c: Likewise.
* gcc.target/aarch64/sve/init_5.c: Likewise.
* gcc.target/aarch64/sve/init_6.c: Likewise.
* gcc.target/aarch64/sve/init_7.c: Likewise.
* gcc.target/aarch64/sve/init_8.c: Likewise.
* gcc.target/aarch64/sve/init_9.c: Likewise.
* gcc.target/aarch64/sve/init_10.c: Likewise.
* gcc.target/aarch64/sve/init_11.c: Likewise.
* gcc.target/aarch64/sve/init_12.c: Likewise.

From-SVN: r273869

16 files changed:
gcc/ChangeLog
gcc/doc/sourcebuild.texi
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.target/aarch64/sve/init_1.c
gcc/testsuite/gcc.target/aarch64/sve/init_10.c
gcc/testsuite/gcc.target/aarch64/sve/init_11.c
gcc/testsuite/gcc.target/aarch64/sve/init_12.c
gcc/testsuite/gcc.target/aarch64/sve/init_2.c
gcc/testsuite/gcc.target/aarch64/sve/init_3.c
gcc/testsuite/gcc.target/aarch64/sve/init_4.c
gcc/testsuite/gcc.target/aarch64/sve/init_5.c
gcc/testsuite/gcc.target/aarch64/sve/init_6.c
gcc/testsuite/gcc.target/aarch64/sve/init_7.c
gcc/testsuite/gcc.target/aarch64/sve/init_8.c
gcc/testsuite/gcc.target/aarch64/sve/init_9.c
gcc/testsuite/lib/scanasm.exp

index 706939c850dc9add4bd202168c64001cd2052018..650201a640c1165b6b0be379cbb093803ce05599 100644 (file)
@@ -1,3 +1,7 @@
+2019-07-29  Richard Sandiford  <richard.sandiford@arm.com>
+
+       * doc/sourcebuild.texi (check-function-bodies): Document.
+
 2019-07-29  Richard Sandiford  <richard.sandiford@arm.com>
 
        * simplify-rtx.c (simplify_const_unary_operation): Fold a
index 6a665154833ef666657f1637dc56294f1e351f02..73186c5853704acfaefb22de859dc53aa37c136f 100644 (file)
@@ -2669,6 +2669,91 @@ assembly output.
 @item scan-not-hidden @var{symbol} [@{ target/xfail @var{selector} @}]
 Passes if @var{symbol} is not defined as a hidden symbol in the test's
 assembly output.
+
+@item check-function-bodies @var{prefix} @var{terminator} [@var{option}]
+Looks through the source file for comments that give the expected assembly
+output for selected functions.  Each line of expected output starts with the
+prefix string @var{prefix} and the expected output for a function as a whole
+is followed by a line that starts with the string @var{terminator}.
+Specifying an empty terminator is equivalent to specifying @samp{"*/"}.
+
+If @var{option} is specified, the test only applies to command lines
+that contain @var{option}.  This can be useful if a source file is compiled
+both with and without optimization, since it is rarely useful to check the
+assembly output for unoptimized code.
+
+The first line of the expected output for a function @var{fn} has the form:
+
+@smallexample
+@var{prefix} @var{fn}:  [@{ target/xfail @var{selector} @}]
+@end smallexample
+
+Subsequent lines of the expected output also start with @var{prefix}.
+In both cases, whitespace after @var{prefix} is not significant.
+
+The test discards assembly directives such as @code{.cfi_startproc}
+and local label definitions such as @code{.LFB0} from the compiler's
+assembly output.  It then matches the result against the expected
+output for a function as a single regular expression.  This means that
+later lines can use backslashes to refer back to @samp{(@dots{})}
+captures on earlier lines.  For example:
+
+@smallexample
+/* @{ dg-final @{ check-function-bodies "**" "" "-DCHECK_ASM" @} @} */
+@dots{}
+/*
+** add_w0_s8_m:
+**     mov     (z[0-9]+\.b), w0
+**     add     z0\.b, p0/m, z0\.b, \1
+**     ret
+*/
+svint8_t add_w0_s8_m (@dots{}) @{ @dots{} @}
+@dots{}
+/*
+** add_b0_s8_m:
+**     mov     (z[0-9]+\.b), b0
+**     add     z1\.b, p0/m, z1\.b, \1
+**     ret
+*/
+svint8_t add_b0_s8_m (@dots{}) @{ @dots{} @}
+@end smallexample
+
+checks whether the implementations of @code{add_w0_s8_m} and
+@code{add_b0_s8_m} match the regular expressions given.  The test only
+runs when @samp{-DCHECK_ASM} is passed on the command line.
+
+It is possible to create non-capturing multi-line regular expression
+groups of the form @samp{(@var{a}|@var{b}|@dots{})} by putting the
+@samp{(}, @samp{|} and @samp{)} on separate lines (each still using
+@var{prefix}).  For example:
+
+@smallexample
+/*
+** cmple_f16_tied:
+** (
+**     fcmge   p0\.h, p0/z, z1\.h, z0\.h
+** |
+**     fcmle   p0\.h, p0/z, z0\.h, z1\.h
+** )
+**     ret
+*/
+svbool_t cmple_f16_tied (@dots{}) @{ @dots{} @}
+@end smallexample
+
+checks whether @code{cmple_f16_tied} is implemented by the
+@code{fcmge} instruction followed by @code{ret} or by the
+@code{fcmle} instruction followed by @code{ret}.  The test is
+still a single regular rexpression.
+
+A line containing just:
+
+@smallexample
+@var{prefix} ...
+@end smallexample
+
+stands for zero or more unmatched lines; the whitespace after
+@var{prefix} is again not significant.
+
 @end table
 
 @subsubsection Scan optimization dump files
index 4230691c11a84d33f90dd2821531e0293d3217e0..f896434fc0bc9978e97ab6627001c7f77ba3c610 100644 (file)
@@ -1,3 +1,21 @@
+2019-07-29  Richard Sandiford  <richard.sandiford@arm.com>
+
+       * lib/scanasm.exp (parse_function_bodies, check_function_body)
+       (check-function-bodies): New procedures.
+       * gcc.target/aarch64/sve/init_1.c: Use check-function-bodies
+       instead of scan-assembler.
+       * gcc.target/aarch64/sve/init_2.c: Likewise.
+       * gcc.target/aarch64/sve/init_3.c: Likewise.
+       * gcc.target/aarch64/sve/init_4.c: Likewise.
+       * gcc.target/aarch64/sve/init_5.c: Likewise.
+       * gcc.target/aarch64/sve/init_6.c: Likewise.
+       * gcc.target/aarch64/sve/init_7.c: Likewise.
+       * gcc.target/aarch64/sve/init_8.c: Likewise.
+       * gcc.target/aarch64/sve/init_9.c: Likewise.
+       * gcc.target/aarch64/sve/init_10.c: Likewise.
+       * gcc.target/aarch64/sve/init_11.c: Likewise.
+       * gcc.target/aarch64/sve/init_12.c: Likewise.
+
 2019-07-28  Rainer Orth  <ro@CeBiTec.Uni-Bielefeld.DE>
 
        * g++.dg/lto/pr89330_0.C (dg-lto-options): Add -fPIC.
index 14abc22e2cb7dbec93c7365b7ec2d59a0c7cd018..8e6004337b3bfc777369330bd7a416f0a9088496 100644 (file)
@@ -1,5 +1,6 @@
 /* { dg-do assemble { target aarch64_asm_sve_ok } } */
 /* { dg-options "-O -msve-vector-bits=256 --save-temps" } */
+/* { dg-final { check-function-bodies "**" "" } } */
 
 /* Case 1.1: Trailing constants with stepped sequence.  */
 
@@ -7,20 +8,15 @@
 
 typedef int32_t vnx4si __attribute__((vector_size (32)));
 
+/*
+** foo:
+**     index   (z[0-9]+\.s), #1, #1
+**     insr    \1, w1
+**     insr    \1, w0
+**     ...
+*/
 __attribute__((noipa))
 vnx4si foo(int a, int b)
 {
   return (vnx4si) { a, b, 1, 2, 3, 4, 5, 6 };
 }
-
-/*
-foo:
-.LFB0:
-        .cfi_startproc
-        index   z0.s, #1, #1
-        insr    z0.s, w1
-        insr    z0.s, w0
-        ret
-*/
-
-/* { dg-final { scan-assembler {\tindex\t(z[0-9]+\.s), #1, #1\n\tinsr\t\1, w1\n\tinsr\t\1, w0} } } */
index c83debe4dac89c18e78ee504fb9e5fa0ef2edd7f..bee039415d0898f4ef26644f2a8c015ef735e5fd 100644 (file)
@@ -1,5 +1,6 @@
 /* { dg-do assemble { target aarch64_asm_sve_ok } } */
 /* { dg-options "-O -msve-vector-bits=256 --save-temps" } */
+/* { dg-final { check-function-bodies "**" "" } } */
 
 /* Case 5.4: Interleaved repeating elements and non-repeating elements.  */
 
@@ -7,22 +8,17 @@
 
 typedef int32_t vnx4si __attribute__((vector_size (32)));
 
+/*
+** foo:
+**     mov     (z[0-9]+\.s), w3
+**     mov     (z[0-9]+\.s), w2
+**     insr    \2, w1
+**     insr    \2, w0
+**     zip1    \2, \2, \1
+**     ...
+*/
 __attribute__((noipa))
 vnx4si foo(int a, int b, int c, int f)
 {
   return (vnx4si) { a, f, b, f, c, f, c, f };
 }
-
-/*
-foo:
-.LFB0:
-        .cfi_startproc
-        mov     z1.s, w3
-        mov     z0.s, w2
-        insr    z0.s, w1
-        insr    z0.s, w0
-        zip1    z0.s, z0.s, z1.s
-        ret
-*/
-
-/* { dg-final { scan-assembler {\tmov\t(z[0-9]+\.s), w3\n\tmov\t(z[0-9]+\.s), w2\n\tinsr\t\2, w1\n\tinsr\t\2, w0\n\tzip1\t\2, \2, \1} } } */
index 90627b44efc7362a606275da4d8f22304d0be83e..8a9496f34e4766390daf6b07c23cd3390eed642a 100644 (file)
@@ -1,5 +1,6 @@
 /* { dg-do assemble { target aarch64_asm_sve_ok } } */
 /* { dg-options "-O -msve-vector-bits=256 --save-temps" } */
+/* { dg-final { check-function-bodies "**" "" } } */
 
 /* Case 5.5: Interleaved repeating elements and trailing same elements.  */
 
@@ -7,21 +8,16 @@
 
 typedef int32_t vnx4si __attribute__((vector_size (32)));
 
+/*
+** foo:
+**     mov     (z[0-9]+\.s), w1
+**     insr    \1, w0
+**     mov     (z[0-9]+\.s), w2
+**     zip1    \1, \1, \2
+**     ...
+*/
 __attribute__((noipa))
 vnx4si foo(int a, int b, int f) 
 {
   return (vnx4si) { a, f, b, f, b, f, b, f };
 }
-
-/*
-foo:
-.LFB0:
-        .cfi_startproc
-        mov     z0.s, w1
-        insr    z0.s, w0
-        mov     z1.s, w2
-        zip1    z0.s, z0.s, z1.s
-        ret
-*/
-
-/* { dg-final { scan-assembler {\tmov\t(z[0-9]+\.s), w1\n\tinsr\t\1, w0\n\tmov\t(z[0-9]+\.s), w2\n\tzip1\t\1, \1, \2} } } */
index dc20e86c02cf52f67c36c78b3796db25662d5758..cbf418e4e6313f640587fc187b8f4740864750fe 100644 (file)
@@ -1,5 +1,6 @@
 /* { dg-do assemble { target aarch64_asm_sve_ok } } */
 /* { dg-options "-O -msve-vector-bits=256 --save-temps" } */
+/* { dg-final { check-function-bodies "**" "" } } */
 
 /* Case 5.5: Interleaved repeating elements and trailing same elements.  */
 
@@ -7,23 +8,18 @@
 
 typedef int32_t vnx4si __attribute__((vector_size (32)));
 
+/*
+** foo:
+**     mov     (z[0-9]+\.s), w2
+**     mov     (z[0-9]+\.s), w0
+**     insr    \2, w1
+**     insr    \2, w1
+**     insr    \2, w1
+**     zip1    \2, \2, \1
+**     ...
+*/
 __attribute__((noipa))
 vnx4si foo(int a, int b, int f) 
 {
   return (vnx4si) { b, f, b, f, b, f, a, f };
 }
-
-/*
-foo:
-.LFB0:
-        .cfi_startproc
-        mov     z1.s, w2
-        mov     z0.s, w0
-        insr    z0.s, w1
-        insr    z0.s, w1
-        insr    z0.s, w1
-        zip1    z0.s, z0.s, z1.s
-        ret
-*/
-
-/* { dg-final { scan-assembler {\tmov\t(z[0-9]+\.s), w2\n\tmov\t(z[0-9]+\.s), w0\n\tinsr\t\2, w1\n\tinsr\t\2, w1\n\tinsr\t\2, w1\n\tzip1\t\2, \2, \1} } } */
index 5b4ba105af26ef975d5b6b222540e94f95c17bd2..83bd999d21edf7c8fdde6b4f72fb971a7632c21d 100644 (file)
@@ -1,5 +1,6 @@
 /* { dg-do assemble { target aarch64_asm_sve_ok } } */
 /* { dg-options "-O -msve-vector-bits=256 --save-temps" } */
+/* { dg-final { check-function-bodies "**" "" } } */
 
 /* Case 1.2: Trailing constants with repeating sequence.  */
 
@@ -7,23 +8,16 @@
 
 typedef int32_t vnx4si __attribute__((vector_size (32)));
 
+/*
+** foo:
+**     ...
+**     ld1w    (z[0-9]+\.s), p[0-9]+/z, \[x[0-9]+\]
+**     insr    \1, w1
+**     insr    \1, w0
+**     ...
+*/
 __attribute__((noipa))
 vnx4si foo(int a, int b)
 {
   return (vnx4si) { a, b, 2, 3, 2, 3, 2, 3 };
 }
-
-/*
-foo:
-.LFB0:
-        .cfi_startproc
-        ptrue   p0.s, vl8
-        adrp    x2, .LANCHOR0
-        add     x2, x2, :lo12:.LANCHOR0
-        ld1w    z0.s, p0/z, [x2]
-        insr    z0.s, w1
-        insr    z0.s, w0
-        ret
-*/
-
-/* { dg-final { scan-assembler {\tld1w\t(z[0-9]+\.s), p[0-9]+/z, \[x[0-9]+\]\n\tinsr\t\1, w1\n\tinsr\t\1, w0} } } */
index 28d218cd768eea9ffe25e4bfa3a9242d686b6ee8..4a418b633f53722c25a2ce3ea148e3c794e5b646 100644 (file)
@@ -1,5 +1,6 @@
 /* { dg-do assemble { target aarch64_asm_sve_ok } } */
 /* { dg-options "-O -msve-vector-bits=256 --save-temps" } */
+/* { dg-final { check-function-bodies "**" "" } } */
 
 /* Case 2.1: Leading constants with stepped sequence.  */
 
@@ -7,21 +8,17 @@
 
 typedef int32_t vnx4si __attribute__((vector_size (32)));
 
+/*
+** foo:
+**     index   (z[0-9]+\.s), #6, #-1
+**     insr    \1, w0
+**     insr    \1, w1
+**     rev     \1, \1
+**     ...
+*/
 __attribute__((noipa))
 vnx4si foo(int a, int b)
 {
   return (vnx4si) { 1, 2, 3, 4, 5, 6, a, b };
 }
 
-/*
-foo:
-.LFB0:
-        .cfi_startproc
-        index   z0.s, #6, #-1
-        insr    z0.s, w0
-        insr    z0.s, w1
-        rev     z0.s, z0.s
-        ret
-*/
-
-/* { dg-final { scan-assembler {\tindex\t(z[0-9]+\.s), #6, #-1\n\tinsr\t\1, w0\n\tinsr\t\1, w1\n\trev\t\1, \1} } } */
index 94484b1a4e66b7e877bc5cb474df9583ac246cf5..fa914488adc6579c9a417addbb81d3370be745a8 100644 (file)
@@ -1,5 +1,6 @@
 /* { dg-do assemble { target aarch64_asm_sve_ok } } */
 /* { dg-options "-O -msve-vector-bits=256 --save-temps" } */
+/* { dg-final { check-function-bodies "**" "" } } */
 
 /* Case 2.2: Leading constants with stepped sequence.  */
 
@@ -7,24 +8,17 @@
 
 typedef int32_t vnx4si __attribute__((vector_size (32)));
 
+/*
+** foo:
+**     ...
+**     ld1w    (z[0-9]+\.s), p[0-9]+/z, \[x[0-9]+\]
+**     insr    \1, w1
+**     insr    \1, w0
+**     rev     \1, \1
+**     ...
+*/
 __attribute__((noipa))
 vnx4si foo(int a, int b)
 {
   return (vnx4si) { 3, 2, 3, 2, 3, 2, b, a };
 }
-
-/*
-foo:
-.LFB0:
-        .cfi_startproc
-        ptrue   p0.s, vl8
-        adrp    x2, .LANCHOR0
-        add     x2, x2, :lo12:.LANCHOR0
-        ld1w    z0.s, p0/z, [x2]
-        insr    z0.s, w1
-        insr    z0.s, w0
-        rev     z0.s, z0.s
-        ret
-*/
-
-/* { dg-final { scan-assembler {\tld1w\t(z[0-9]+\.s), p[0-9]+/z, \[x[0-9]+\]\n\tinsr\t\1, w1\n\tinsr\t\1, w0\n\trev\t\1, \1} } } */
index a43dd7a4ac7ceb49a134e2759fc8de57370a0d30..794e265c3b8f9312c5b0163a61fc7610147ba14f 100644 (file)
@@ -1,5 +1,6 @@
 /* { dg-do assemble { target aarch64_asm_sve_ok } } */
 /* { dg-options "-O -msve-vector-bits=256 --save-temps" } */
+/* { dg-final { check-function-bodies "**" "" } } */
 
 /* Case 3: Trailing same element.  */ 
 
@@ -7,20 +8,15 @@
 
 typedef int32_t vnx4si __attribute__((vector_size (32)));
 
+/*
+** foo:
+**     mov     (z[0-9]+\.s), w2
+**     insr    \1, w1
+**     insr    \1, w0
+**     ...
+*/
 __attribute__((noipa))
 vnx4si foo(int a, int b, int c)
 {
   return (vnx4si) { a, b, c, c, c, c, c, c };
 }
-
-/*
-foo:
-.LFB0:
-        .cfi_startproc
-        mov     z0.s, w2
-        insr    z0.s, w1
-        insr    z0.s, w0
-        ret
-*/
-
-/* { dg-final { scan-assembler {\tmov\t(z[0-9]+\.s), w2\n\tinsr\t\1, w1\n\tinsr\t\1, w0} } } */
index b8e30fb72ebd10a949ed91163613f8f7cdfd17a3..8443fc0000e3463c4f8926ae8e3a3130754cf8f4 100644 (file)
@@ -1,5 +1,6 @@
 /* { dg-do assemble { target aarch64_asm_sve_ok } } */
 /* { dg-options "-O -msve-vector-bits=256 --save-temps" } */
+/* { dg-final { check-function-bodies "**" "" } } */
 
 /* Case 3: Trailing same element.  */ 
 
@@ -7,21 +8,16 @@
 
 typedef int32_t vnx4si __attribute__((vector_size (32)));
 
+/*
+** foo:
+**     mov     (z[0-9]+\.s), w2
+**     insr    \1, w1
+**     insr    \1, w0
+**     rev     \1, \1
+**     ...
+*/
 __attribute__((noipa))
 vnx4si foo(int a, int b, int c)
 {
   return (vnx4si) { c, c, c, c, c, c, b, a };
 }
-
-/*
-foo:
-.LFB0:
-        .cfi_startproc
-        mov     z0.s, w2
-        insr    z0.s, w1
-        insr    z0.s, w0
-        rev     z0.s, z0.s
-        ret
-*/
-
-/* { dg-final { scan-assembler {\tmov\t(z[0-9]+\.s), w2\n\tinsr\t\1, w1\n\tinsr\t\1, w0\n\trev\t\1, \1} } } */
index dd27978faf7e676bd1859f9347a7b1b038694c29..63dbbbe61f6bc879978072a0a9613a6595790051 100644 (file)
@@ -1,5 +1,6 @@
 /* { dg-do assemble { target aarch64_asm_sve_ok } } */
 /* { dg-options "-O -msve-vector-bits=256 --save-temps" } */
+/* { dg-final { check-function-bodies "**" "" } } */
 
 /* Case 5.1: All elements.  */ 
 
@@ -7,25 +8,20 @@
 
 typedef int32_t vnx4si __attribute__((vector_size (32)));
 
+/*
+** foo:
+**     mov     (z[0-9]+\.s), w7
+**     insr    \1, w6
+**     insr    \1, w5
+**     insr    \1, w4
+**     insr    \1, w3
+**     insr    \1, w2
+**     insr    \1, w1
+**     insr    \1, w0
+**     ...
+*/
 __attribute__((noipa))
 vnx4si foo(int a, int b, int c, int d, int e, int f, int g, int h)
 {
   return (vnx4si) { a, b, c, d, e, f, g, h };
 }
-
-/*
-foo:
-.LFB0:
-        .cfi_startproc
-        mov     z0.s, w7
-        insr    z0.s, w6
-        insr    z0.s, w5
-        insr    z0.s, w4
-        insr    z0.s, w3
-        insr    z0.s, w2
-        insr    z0.s, w1
-        insr    z0.s, w0
-        ret
-*/
-
-/* { dg-final { scan-assembler {\tmov\t(z[0-9]+\.s), w7\n\tinsr\t\1, w6\n\tinsr\t\1, w5\n\tinsr\t\1, w4\n\tinsr\t\1, w3\n\tinsr\t\1, w2\n\tinsr\t\1, w1\n\tinsr\t\1, w0} } } */
index 73f7aba3df3d8fa973cbf35c268f8c45760d817a..9c2456785d53c1c66a272fa89f06abdd157d5c94 100644 (file)
@@ -1,5 +1,6 @@
 /* { dg-do assemble { target aarch64_asm_sve_ok } } */
 /* { dg-options "-O -msve-vector-bits=256 --save-temps" } */
+/* { dg-final { check-function-bodies "**" "" } } */
 
 /* Case 5.2: Interleaved elements and constants.  */ 
 
@@ -7,26 +8,19 @@
 
 typedef int32_t vnx4si __attribute__((vector_size (32)));
 
+/*
+** foo:
+**     ...
+**     ld1w    (z[0-9]+\.s), p[0-9]+/z, \[x[0-9]+\]
+**     mov     (z[0-9]+\.s), w3
+**     insr    \2, w2
+**     insr    \2, w1
+**     insr    \2, w0
+**     zip1    \2, \2, \1
+**     ...
+*/
 __attribute__((noipa))
 vnx4si foo(int a, int b, int c, int d)
 {
   return (vnx4si) { a, 1, b, 2, c, 3, d, 4 }; 
 }
-
-/*
-foo:
-.LFB0:
-        .cfi_startproc
-        ptrue   p0.s, vl8
-        adrp    x4, .LANCHOR0
-        add     x4, x4, :lo12:.LANCHOR0
-        ld1w    z1.s, p0/z, [x4]
-        mov     z0.s, w3
-        insr    z0.s, w2
-        insr    z0.s, w1
-        insr    z0.s, w0
-        zip1    z0.s, z0.s, z1.s
-        ret
-*/
-
-/* { dg-final { scan-assembler {\tld1w\t(z[0-9]+\.s), p[0-9]+/z, \[x[0-9]+\]\n\tmov\t(z[0-9]+\.s), w3\n\tinsr\t\2, w2\n\tinsr\t\2, w1\n\tinsr\t\2, w0\n\tzip1\t\2, \2, \1} } } */
index 2cc564a5a8395b06b8b0ad12c53524e5ac704fe6..d22ab71e696ceaaa47dd3e32d2b7a44211b4d667 100644 (file)
@@ -1,5 +1,6 @@
 /* { dg-do assemble { target aarch64_asm_sve_ok } } */
 /* { dg-options "-O -msve-vector-bits=256 --save-temps" } */
+/* { dg-final { check-function-bodies "**" "" } } */
 
 /* Case 5.3: Repeated elements.  */ 
 
@@ -7,20 +8,15 @@
 
 typedef int32_t vnx4si __attribute__((vector_size (32)));
 
+/*
+** foo:
+**     mov     (z[0-9]+\.s), w0
+**     mov     (z[0-9]+\.s), w1
+**     zip1    \1, \1, \2
+**     ...
+*/
 __attribute__((noipa))
 vnx4si foo(int a, int b)
 {
   return (vnx4si) { a, b, a, b, a, b, a, b };
 }
-
-/*
-foo:
-.LFB0:
-        .cfi_startproc
-        mov     z0.s, w0
-        mov     z1.s, w1
-        zip1    z0.s, z0.s, z1.s
-        ret
-*/
-
-/* { dg-final { scan-assembler {\tmov\t(z[0-9]+\.s), w0\n\tmov\t(z[0-9]+\.s), w1\n\tzip1\t\1, \1, \2} } } */
index 231a4d66bad1529bfa3dd3704a297c4471d0df52..0f1b246b8dc5d177e01bd5b03cc44c4f40eadaa1 100644 (file)
@@ -554,3 +554,169 @@ proc scan-lto-assembler { args } {
     verbose "output_file: $output_file"
     dg-scan "scan-lto-assembler" 1 $testcase $output_file $args
 }
+
+# Read assembly file FILENAME and store a mapping from function names
+# to function bodies in array RESULT.  FILENAME has already been uploaded
+# locally where necessary and is known to exist.
+
+proc parse_function_bodies { filename result } {
+    upvar $result up_result
+
+    # Regexp for the start of a function definition (name in \1).
+    set label {^([a-zA-Z_]\S+):$}
+
+    # Regexp for the end of a function definition.
+    set terminator {^\s*\.size}
+
+    # Regexp for lines that aren't interesting.
+    set fluff {^\s*(?:\.|//)}
+
+    set fd [open $filename r]
+    set in_function 0
+    while { [gets $fd line] >= 0 } {
+       if { [regexp $label $line dummy function_name] } {
+           set in_function 1
+           set function_body ""
+       } elseif { $in_function } {
+           if { [regexp $terminator $line] } {
+               set up_result($function_name) $function_body
+               set in_function 0
+           } elseif { ![regexp $fluff $line] } {
+               append function_body $line "\n"
+           }
+       }
+    }
+    close $fd
+}
+
+# FUNCTIONS is an array that maps function names to function bodies.
+# Return true if it contains a definition of function NAME and if
+# that definition matches BODY_REGEXP.
+
+proc check_function_body { functions name body_regexp } {
+    upvar $functions up_functions
+
+    if { ![info exists up_functions($name)] } {
+       return 0
+    }
+    return [regexp "^$body_regexp\$" $up_functions($name)]
+}
+
+# Check the implementations of functions against expected output.  Used as:
+#
+# { dg-do { check-function-bodies PREFIX TERMINATOR[ OPTION] } }
+#
+# See sourcebuild.texi for details.
+
+proc check-function-bodies { args } {
+    if { [llength $args] < 2 } {
+       error "too few arguments to check-function-bodies"
+    }
+    if { [llength $args] > 3 } {
+       error "too many arguments to check-function-bodies"
+    }
+
+    if { [llength $args] == 3 } {
+       set required_flag [lindex $args 2]
+
+       upvar 2 dg-extra-tool-flags extra_tool_flags
+       set flags $extra_tool_flags
+
+       global torture_current_flags
+       if { [info exists torture_current_flags] } {
+           append flags " " $torture_current_flags
+       }
+       if { ![regexp " $required_flag " $flags] } {
+           return
+       }
+    }
+
+    set testcase [testname-for-summary]
+    # The name might include a list of options; extract the file name.
+    set filename [lindex $testcase 0]
+
+    global srcdir
+    set input_filename "$srcdir/$filename"
+    set output_filename "[file rootname [file tail $filename]].s"
+
+    set prefix [lindex $args 0]
+    set prefix_len [string length $prefix]
+    set terminator [lindex $args 1]
+    if { [string equal $terminator ""] } {
+       set terminator "*/"
+    }
+    set terminator_len [string length $terminator]
+
+    set have_bodies 0
+    if { [is_remote host] } {
+       remote_upload host "$filename"
+    }
+    if { [file exists $output_filename] } {
+       parse_function_bodies $output_filename functions
+       set have_bodies 1
+    } else {
+       verbose -log "$testcase: output file does not exist"
+    }
+
+    set count 0
+    set function_regexp ""
+    set label {^(\S+):$}
+
+    set lineno 1
+    set fd [open $input_filename r]
+    set in_function 0
+    while { [gets $fd line] >= 0 } {
+       if { [string equal -length $prefix_len $line $prefix] } {
+           set line [string trim [string range $line $prefix_len end]]
+           if { !$in_function } {
+               if { [regexp "^(.*\\S)\\s+{(.*)}\$" $line dummy \
+                         line selector] } {
+                   set selector [dg-process-target $selector]
+               } else {
+                   set selector "P"
+               }
+               if { ![regexp $label $line dummy function_name] } {
+                   close $fd
+                   error "check-function-bodies: line $lineno does not have a function label"
+               }
+               set in_function 1
+               set function_regexp ""
+           } elseif { [string equal $line "("] } {
+               append function_regexp "(?:"
+           } elseif { [string equal $line "|"] } {
+               append function_regexp "|"
+           } elseif { [string equal $line ")"] } {
+               append function_regexp ")"
+           } elseif { [string equal $line "..."] } {
+               append function_regexp ".*"
+           } else {
+               append function_regexp "\t" $line "\n"
+           }
+       } elseif { [string equal -length $terminator_len $line $terminator] } {
+           if { ![string equal $selector "N"] } {
+               if { [string equal $selector "F"] } {
+                   setup_xfail "*-*-*"
+               }
+               set testname "$testcase check-function-bodies $function_name"
+               if { !$have_bodies } {
+                   unresolved $testname
+               } elseif { [check_function_body functions $function_name \
+                               $function_regexp] } {
+                   pass $testname
+               } else {
+                   fail $testname
+               }
+           }
+           set in_function 0
+           incr count
+       }
+       incr lineno
+    }
+    close $fd
+    if { $in_function } {
+       error "check-function-bodies: missing \"$terminator\""
+    }
+    if { $count == 0 } {
+       error "check-function-bodies: no matches found"
+    }
+}