Commit 4d706ff8 by Richard Sandiford Committed by Richard Sandiford

Add dg test for matching function bodies

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
parent 708cc613
2019-07-29 Richard Sandiford <richard.sandiford@arm.com> 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 * simplify-rtx.c (simplify_const_unary_operation): Fold a
VEC_DUPLICATE of a fixed-length vector even if the result VEC_DUPLICATE of a fixed-length vector even if the result
is variable-length. Likewise fold a duplicate of a is variable-length. Likewise fold a duplicate of a
......
...@@ -2669,6 +2669,91 @@ assembly output. ...@@ -2669,6 +2669,91 @@ assembly output.
@item scan-not-hidden @var{symbol} [@{ target/xfail @var{selector} @}] @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 Passes if @var{symbol} is not defined as a hidden symbol in the test's
assembly output. 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 @end table
@subsubsection Scan optimization dump files @subsubsection Scan optimization dump files
......
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> 2019-07-28 Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE>
* g++.dg/lto/pr89330_0.C (dg-lto-options): Add -fPIC. * g++.dg/lto/pr89330_0.C (dg-lto-options): Add -fPIC.
......
/* { dg-do assemble { target aarch64_asm_sve_ok } } */ /* { dg-do assemble { target aarch64_asm_sve_ok } } */
/* { dg-options "-O -msve-vector-bits=256 --save-temps" } */ /* { dg-options "-O -msve-vector-bits=256 --save-temps" } */
/* { dg-final { check-function-bodies "**" "" } } */
/* Case 1.1: Trailing constants with stepped sequence. */ /* Case 1.1: Trailing constants with stepped sequence. */
...@@ -7,20 +8,15 @@ ...@@ -7,20 +8,15 @@
typedef int32_t vnx4si __attribute__((vector_size (32))); typedef int32_t vnx4si __attribute__((vector_size (32)));
/*
** foo:
** index (z[0-9]+\.s), #1, #1
** insr \1, w1
** insr \1, w0
** ...
*/
__attribute__((noipa)) __attribute__((noipa))
vnx4si foo(int a, int b) vnx4si foo(int a, int b)
{ {
return (vnx4si) { a, b, 1, 2, 3, 4, 5, 6 }; 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} } } */
/* { dg-do assemble { target aarch64_asm_sve_ok } } */ /* { dg-do assemble { target aarch64_asm_sve_ok } } */
/* { dg-options "-O -msve-vector-bits=256 --save-temps" } */ /* { dg-options "-O -msve-vector-bits=256 --save-temps" } */
/* { dg-final { check-function-bodies "**" "" } } */
/* Case 5.4: Interleaved repeating elements and non-repeating elements. */ /* Case 5.4: Interleaved repeating elements and non-repeating elements. */
...@@ -7,22 +8,17 @@ ...@@ -7,22 +8,17 @@
typedef int32_t vnx4si __attribute__((vector_size (32))); 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)) __attribute__((noipa))
vnx4si foo(int a, int b, int c, int f) vnx4si foo(int a, int b, int c, int f)
{ {
return (vnx4si) { a, f, b, f, c, f, c, 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} } } */
/* { dg-do assemble { target aarch64_asm_sve_ok } } */ /* { dg-do assemble { target aarch64_asm_sve_ok } } */
/* { dg-options "-O -msve-vector-bits=256 --save-temps" } */ /* { dg-options "-O -msve-vector-bits=256 --save-temps" } */
/* { dg-final { check-function-bodies "**" "" } } */
/* Case 5.5: Interleaved repeating elements and trailing same elements. */ /* Case 5.5: Interleaved repeating elements and trailing same elements. */
...@@ -7,21 +8,16 @@ ...@@ -7,21 +8,16 @@
typedef int32_t vnx4si __attribute__((vector_size (32))); 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)) __attribute__((noipa))
vnx4si foo(int a, int b, int f) vnx4si foo(int a, int b, int f)
{ {
return (vnx4si) { a, f, b, f, b, f, b, 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} } } */
/* { dg-do assemble { target aarch64_asm_sve_ok } } */ /* { dg-do assemble { target aarch64_asm_sve_ok } } */
/* { dg-options "-O -msve-vector-bits=256 --save-temps" } */ /* { dg-options "-O -msve-vector-bits=256 --save-temps" } */
/* { dg-final { check-function-bodies "**" "" } } */
/* Case 5.5: Interleaved repeating elements and trailing same elements. */ /* Case 5.5: Interleaved repeating elements and trailing same elements. */
...@@ -7,23 +8,18 @@ ...@@ -7,23 +8,18 @@
typedef int32_t vnx4si __attribute__((vector_size (32))); 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)) __attribute__((noipa))
vnx4si foo(int a, int b, int f) vnx4si foo(int a, int b, int f)
{ {
return (vnx4si) { b, f, b, f, b, f, a, 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} } } */
/* { dg-do assemble { target aarch64_asm_sve_ok } } */ /* { dg-do assemble { target aarch64_asm_sve_ok } } */
/* { dg-options "-O -msve-vector-bits=256 --save-temps" } */ /* { dg-options "-O -msve-vector-bits=256 --save-temps" } */
/* { dg-final { check-function-bodies "**" "" } } */
/* Case 1.2: Trailing constants with repeating sequence. */ /* Case 1.2: Trailing constants with repeating sequence. */
...@@ -7,23 +8,16 @@ ...@@ -7,23 +8,16 @@
typedef int32_t vnx4si __attribute__((vector_size (32))); 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)) __attribute__((noipa))
vnx4si foo(int a, int b) vnx4si foo(int a, int b)
{ {
return (vnx4si) { a, b, 2, 3, 2, 3, 2, 3 }; 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} } } */
/* { dg-do assemble { target aarch64_asm_sve_ok } } */ /* { dg-do assemble { target aarch64_asm_sve_ok } } */
/* { dg-options "-O -msve-vector-bits=256 --save-temps" } */ /* { dg-options "-O -msve-vector-bits=256 --save-temps" } */
/* { dg-final { check-function-bodies "**" "" } } */
/* Case 2.1: Leading constants with stepped sequence. */ /* Case 2.1: Leading constants with stepped sequence. */
...@@ -7,21 +8,17 @@ ...@@ -7,21 +8,17 @@
typedef int32_t vnx4si __attribute__((vector_size (32))); 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)) __attribute__((noipa))
vnx4si foo(int a, int b) vnx4si foo(int a, int b)
{ {
return (vnx4si) { 1, 2, 3, 4, 5, 6, a, 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} } } */
/* { dg-do assemble { target aarch64_asm_sve_ok } } */ /* { dg-do assemble { target aarch64_asm_sve_ok } } */
/* { dg-options "-O -msve-vector-bits=256 --save-temps" } */ /* { dg-options "-O -msve-vector-bits=256 --save-temps" } */
/* { dg-final { check-function-bodies "**" "" } } */
/* Case 2.2: Leading constants with stepped sequence. */ /* Case 2.2: Leading constants with stepped sequence. */
...@@ -7,24 +8,17 @@ ...@@ -7,24 +8,17 @@
typedef int32_t vnx4si __attribute__((vector_size (32))); 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)) __attribute__((noipa))
vnx4si foo(int a, int b) vnx4si foo(int a, int b)
{ {
return (vnx4si) { 3, 2, 3, 2, 3, 2, b, a }; 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} } } */
/* { dg-do assemble { target aarch64_asm_sve_ok } } */ /* { dg-do assemble { target aarch64_asm_sve_ok } } */
/* { dg-options "-O -msve-vector-bits=256 --save-temps" } */ /* { dg-options "-O -msve-vector-bits=256 --save-temps" } */
/* { dg-final { check-function-bodies "**" "" } } */
/* Case 3: Trailing same element. */ /* Case 3: Trailing same element. */
...@@ -7,20 +8,15 @@ ...@@ -7,20 +8,15 @@
typedef int32_t vnx4si __attribute__((vector_size (32))); typedef int32_t vnx4si __attribute__((vector_size (32)));
/*
** foo:
** mov (z[0-9]+\.s), w2
** insr \1, w1
** insr \1, w0
** ...
*/
__attribute__((noipa)) __attribute__((noipa))
vnx4si foo(int a, int b, int c) vnx4si foo(int a, int b, int c)
{ {
return (vnx4si) { a, b, c, c, c, c, c, 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} } } */
/* { dg-do assemble { target aarch64_asm_sve_ok } } */ /* { dg-do assemble { target aarch64_asm_sve_ok } } */
/* { dg-options "-O -msve-vector-bits=256 --save-temps" } */ /* { dg-options "-O -msve-vector-bits=256 --save-temps" } */
/* { dg-final { check-function-bodies "**" "" } } */
/* Case 3: Trailing same element. */ /* Case 3: Trailing same element. */
...@@ -7,21 +8,16 @@ ...@@ -7,21 +8,16 @@
typedef int32_t vnx4si __attribute__((vector_size (32))); 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)) __attribute__((noipa))
vnx4si foo(int a, int b, int c) vnx4si foo(int a, int b, int c)
{ {
return (vnx4si) { c, c, c, c, c, c, b, a }; 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} } } */
/* { dg-do assemble { target aarch64_asm_sve_ok } } */ /* { dg-do assemble { target aarch64_asm_sve_ok } } */
/* { dg-options "-O -msve-vector-bits=256 --save-temps" } */ /* { dg-options "-O -msve-vector-bits=256 --save-temps" } */
/* { dg-final { check-function-bodies "**" "" } } */
/* Case 5.1: All elements. */ /* Case 5.1: All elements. */
...@@ -7,25 +8,20 @@ ...@@ -7,25 +8,20 @@
typedef int32_t vnx4si __attribute__((vector_size (32))); 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)) __attribute__((noipa))
vnx4si foo(int a, int b, int c, int d, int e, int f, int g, int h) 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 }; 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} } } */
/* { dg-do assemble { target aarch64_asm_sve_ok } } */ /* { dg-do assemble { target aarch64_asm_sve_ok } } */
/* { dg-options "-O -msve-vector-bits=256 --save-temps" } */ /* { dg-options "-O -msve-vector-bits=256 --save-temps" } */
/* { dg-final { check-function-bodies "**" "" } } */
/* Case 5.2: Interleaved elements and constants. */ /* Case 5.2: Interleaved elements and constants. */
...@@ -7,26 +8,19 @@ ...@@ -7,26 +8,19 @@
typedef int32_t vnx4si __attribute__((vector_size (32))); 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)) __attribute__((noipa))
vnx4si foo(int a, int b, int c, int d) vnx4si foo(int a, int b, int c, int d)
{ {
return (vnx4si) { a, 1, b, 2, c, 3, d, 4 }; 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} } } */
/* { dg-do assemble { target aarch64_asm_sve_ok } } */ /* { dg-do assemble { target aarch64_asm_sve_ok } } */
/* { dg-options "-O -msve-vector-bits=256 --save-temps" } */ /* { dg-options "-O -msve-vector-bits=256 --save-temps" } */
/* { dg-final { check-function-bodies "**" "" } } */
/* Case 5.3: Repeated elements. */ /* Case 5.3: Repeated elements. */
...@@ -7,20 +8,15 @@ ...@@ -7,20 +8,15 @@
typedef int32_t vnx4si __attribute__((vector_size (32))); 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)) __attribute__((noipa))
vnx4si foo(int a, int b) vnx4si foo(int a, int b)
{ {
return (vnx4si) { a, b, a, b, a, b, a, 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} } } */
...@@ -554,3 +554,169 @@ proc scan-lto-assembler { args } { ...@@ -554,3 +554,169 @@ proc scan-lto-assembler { args } {
verbose "output_file: $output_file" verbose "output_file: $output_file"
dg-scan "scan-lto-assembler" 1 $testcase $output_file $args 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"
}
}
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