The aarch64 backend expanded for 8/16/32 bit CRCs only and skipped
64-bit CRC expansion. This patch extends the routines to also support
64-bit CRC for both Bit-Forward and Bit-Reversed similar to
x86 clmul implementation.
gcc/ChangeLog:
* config/aarch64/aarch64.cc (aarch64_crc_constants_gen): New
function.
(aarch64_expand_crc_using_pmull): Added support for 64-bit CRCs.
(aarch64_expand_reversed_crc_using_pmull): Likewise.
* config/aarch64/aarch64.md (crc_rev<ALLI:mode><ALLX:mode>4):
Renamed ALLX to ALLI_2 to allow 64-bit CRC.
(crc_rev<ALLI:mode><ALLI_2:mode>4): Likewise.
(crc<ALLI:mode><ALLX:mode>4): Likewise.
(crc<ALLI:mode><ALLI_2:mode>4): Likewise.
* config/aarch64/iterators.md: Added new mode iterator ALLI_2
which duplicates ALLI.
gcc/testsuite/ChangeLog:
* gcc.target/aarch64/crc-34-pmul.c: New test.
* gcc.target/aarch64/crc-35-pmul.c: New test.
* gcc.target/aarch64/crc-36-pmul.c: New test.
* gcc.target/aarch64/crc-37-pmul.c: New test.
* gcc.target/aarch64/crc-38-pmul.c: New test.
* gcc.target/aarch64/crc-39-pmul.c: New test.
* gcc.target/aarch64/crc-40-pmul.c: New test.
* gcc.target/aarch64/crc-41-pmul.c: New test.
Signed-off-by: Shreesh Adiga <[email protected]>
---
gcc/config/aarch64/aarch64.cc | 136 +++++++++++++++---
gcc/config/aarch64/aarch64.md | 32 +++--
gcc/config/aarch64/iterators.md | 3 +
.../gcc.target/aarch64/crc-34-pmul.c | 9 ++
.../gcc.target/aarch64/crc-35-pmul.c | 9 ++
.../gcc.target/aarch64/crc-36-pmul.c | 9 ++
.../gcc.target/aarch64/crc-37-pmul.c | 9 ++
.../gcc.target/aarch64/crc-38-pmul.c | 9 ++
.../gcc.target/aarch64/crc-39-pmul.c | 9 ++
.../gcc.target/aarch64/crc-40-pmul.c | 9 ++
.../gcc.target/aarch64/crc-41-pmul.c | 9 ++
11 files changed, 207 insertions(+), 36 deletions(-)
create mode 100644 gcc/testsuite/gcc.target/aarch64/crc-34-pmul.c
create mode 100644 gcc/testsuite/gcc.target/aarch64/crc-35-pmul.c
create mode 100644 gcc/testsuite/gcc.target/aarch64/crc-36-pmul.c
create mode 100644 gcc/testsuite/gcc.target/aarch64/crc-37-pmul.c
create mode 100644 gcc/testsuite/gcc.target/aarch64/crc-38-pmul.c
create mode 100644 gcc/testsuite/gcc.target/aarch64/crc-39-pmul.c
create mode 100644 gcc/testsuite/gcc.target/aarch64/crc-40-pmul.c
create mode 100644 gcc/testsuite/gcc.target/aarch64/crc-41-pmul.c
diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc
index 5b1c78462a3..ae61beda396 100644
--- a/gcc/config/aarch64/aarch64.cc
+++ b/gcc/config/aarch64/aarch64.cc
@@ -33860,6 +33860,22 @@ aarch64::report_not_enum (location_t location, tree
fndecl, unsigned int argno,
" a valid %qT value", actual, argno + 1, fndecl, enumtype);
}
+/* Generate V2DImode reg with the required 64-bit pmull constants.
+ Mainly written to handle endianness for the lanes. */
+static rtx
+aarch64_crc_constants_gen (unsigned HOST_WIDE_INT lo,
+ unsigned HOST_WIDE_INT hi)
+{
+ rtx lo_rtx = gen_int_mode (lo, DImode);
+ rtx hi_rtx = gen_int_mode (hi, DImode);
+ rtvec constants_vec = (BYTES_BIG_ENDIAN
+ ? gen_rtvec (2, hi_rtx, lo_rtx)
+ : gen_rtvec (2, lo_rtx, hi_rtx));
+ rtx reg = gen_reg_rtx (V2DImode);
+ emit_move_insn (reg, gen_rtx_CONST_VECTOR (V2DImode, constants_vec));
+ return reg;
+}
+
/* Generate assembly to calculate CRC
using carry-less multiplication instruction.
OPERANDS[1] is input CRC,
@@ -33880,7 +33896,7 @@ aarch64_expand_crc_using_pmull (scalar_mode crc_mode,
unsigned HOST_WIDE_INT crc_size = GET_MODE_BITSIZE (crc_mode);
unsigned HOST_WIDE_INT data_size = GET_MODE_BITSIZE (data_mode);
- gcc_assert (crc_size <= 32);
+ gcc_assert (crc_size <= 64);
gcc_assert (data_size <= crc_size);
/* Calculate the quotient. */
@@ -33891,21 +33907,57 @@ aarch64_expand_crc_using_pmull (scalar_mode crc_mode,
crc = expand_shift (RSHIFT_EXPR, DImode, crc, crc_size - data_size,
NULL_RTX, 1);
- rtx t0 = force_reg (DImode, gen_int_mode (q, DImode));
+ rtx t0, t1, a0_x2;
+ rtx constants_reg;
polynomial = simplify_gen_unary (ZERO_EXTEND, DImode, polynomial,
GET_MODE (polynomial));
- rtx t1 = force_reg (DImode, polynomial);
rtx a0 = expand_binop (DImode, xor_optab, crc, data, NULL_RTX, 1,
OPTAB_WIDEN);
+ if (crc_size == 64)
+ {
+ /* Pack the 64-bit quotient and Polynomial pmull constants into a single
+ 128-bit V2DImode constant and load it from memory.
+ a0 is loaded into both lanes as it is needed for performing
+ xor with upper lane after first clmul.
+ Since we need upper 64-bits of pmull (a0, q) for second pmull with
+ polynomial, polynomial is set at lane 1. */
+ constants_reg = aarch64_crc_constants_gen (q, UINTVAL (polynomial));
+ a0_x2 = gen_reg_rtx (V2DImode);
+ rtx dup = gen_rtx_VEC_DUPLICATE (V2DImode, a0);
+ emit_move_insn (a0_x2, dup);
+ t0 = gen_lowpart (DImode, constants_reg);
+ }
+ else
+ {
+ t0 = force_reg (DImode, gen_int_mode (q, DImode));
+ t1 = force_reg (DImode, polynomial);
+ }
+
+ /* Perform carry-less multiplication with quotient. */
rtx pmull_res = gen_reg_rtx (TImode);
emit_insn (gen_aarch64_crypto_pmulldi (pmull_res, a0, t0));
- a0 = gen_lowpart (DImode, pmull_res);
- a0 = expand_shift (RSHIFT_EXPR, DImode, a0, crc_size, NULL_RTX, 1);
+ if (crc_size == 64)
+ {
+ /* Perform xor of a0 with upper 64-bits of pmull_res to handle the
+ 65th bit of quotient. */
+ rtx pmull_vec = gen_lowpart (V2DImode, pmull_res);
+ pmull_vec = expand_binop (V2DImode, xor_optab, pmull_vec, a0_x2,
+ NULL_RTX, 1, OPTAB_DIRECT);
+ /* Perform carry-less multiplication with polynomial. */
+ emit_insn (gen_aarch64_crypto_pmullv2di (pmull_res,
+ constants_reg, pmull_vec));
+ }
+ else
+ {
+ a0 = gen_lowpart (DImode, pmull_res);
+ a0 = expand_shift (RSHIFT_EXPR, DImode, a0, crc_size, NULL_RTX, 1);
+ /* Perform carry-less multiplication with polynomial. */
+ emit_insn (gen_aarch64_crypto_pmulldi (pmull_res, a0, t1));
+ }
- emit_insn (gen_aarch64_crypto_pmulldi (pmull_res, a0, t1));
a0 = gen_lowpart (DImode, pmull_res);
if (crc_size > data_size)
@@ -33939,41 +33991,83 @@ aarch64_expand_reversed_crc_using_pmull (scalar_mode
crc_mode,
unsigned HOST_WIDE_INT crc_size = GET_MODE_BITSIZE (crc_mode);
unsigned HOST_WIDE_INT data_size = GET_MODE_BITSIZE (data_mode);
- gcc_assert (crc_size <= 32);
+ gcc_assert (crc_size <= 64);
gcc_assert (data_size <= crc_size);
/* Calculate the quotient. */
unsigned HOST_WIDE_INT
q = gf2n_poly_long_div_quotient (UINTVAL (polynomial), crc_size);
/* Reflect the calculated quotient. */
- q = reflect_hwi (q, crc_size + 1);
- rtx t0 = force_reg (DImode, gen_int_mode (q, DImode));
+ q = (reflect_hwi (q, crc_size) << 1) + 1;
/* Reflect the polynomial. */
unsigned HOST_WIDE_INT ref_polynomial = reflect_hwi (UINTVAL (polynomial),
crc_size);
- /* An unshifted multiplier would require the final result to be extracted
- using a shift right by DATA_SIZE - 1 bits. Shift the multiplier left
- so that the shift right can be by CRC_SIZE bits instead. */
- ref_polynomial <<= crc_size - data_size + 1;
- rtx t1 = force_reg (DImode, gen_int_mode (ref_polynomial, DImode));
/* CRC calculation's main part. */
rtx a0 = expand_binop (DImode, xor_optab, crc, data, NULL_RTX, 1,
OPTAB_WIDEN);
- /* Perform carry-less multiplication and get low part. */
rtx pmull_res = gen_reg_rtx (TImode);
- emit_insn (gen_aarch64_crypto_pmulldi (pmull_res, a0, t0));
- a0 = gen_lowpart (DImode, pmull_res);
- a0 = expand_binop (DImode, and_optab, a0,
- gen_int_mode (GET_MODE_MASK (data_mode), DImode),
- NULL_RTX, 1, OPTAB_WIDEN);
+ rtx t0, t1, a0_x2, constants_reg;
+ if (crc_size == 64)
+ {
+ /* Pack the 64-bit quotient and Polynomial pmull constants into a single
+ 128-bit V2DImode constant and load it from memory.
+ a0 is loaded into lane 1, so that we can use PMULL2 with quotient.
+ Since we need lower 64-bits of pmull (a0, q) for second pmull with
+ polynomial, polynomial is set at lane 0. */
+ constants_reg = aarch64_crc_constants_gen (ref_polynomial << 1, q);
+ a0_x2 = gen_reg_rtx (V2DImode);
+ rtx dup = gen_rtx_VEC_DUPLICATE (V2DImode, a0);
+ emit_move_insn (a0_x2, dup);
+ /* Perform carry-less multiplication with quotient and get low part. */
+ emit_insn (gen_aarch64_crypto_pmullv2di (pmull_res,
+ constants_reg, a0_x2));
+ rtx pmull_vec = gen_lowpart (V2DImode, pmull_res);
+ if (data_size < 64)
+ pmull_vec = expand_shift (LSHIFT_EXPR, V2DImode, pmull_vec,
+ 64 - data_size, NULL_RTX, 0);
+
+ a0 = gen_lowpart (DImode, pmull_vec);
+ t1 = gen_lowpart (DImode, constants_reg);
+ /* Regenerate pmull_res to preserve a0 needed for xor later. */
+ pmull_res = gen_reg_rtx (TImode);
+ }
+ else
+ {
+ /* An unshifted multiplier would require the final result to be extracted
+ using a shift right by DATA_SIZE - 1 bits. Shift the multiplier left
+ so that the shift right can be by CRC_SIZE bits instead. */
+ ref_polynomial <<= crc_size - data_size + 1;
+ t0 = force_reg (DImode, gen_int_mode (q, DImode));
+ t1 = force_reg (DImode, gen_int_mode (ref_polynomial, DImode));
+ /* Perform carry-less multiplication and get low part. */
+ emit_insn (gen_aarch64_crypto_pmulldi (pmull_res, a0, t0));
+ a0 = gen_lowpart (DImode, pmull_res);
+
+ a0 = expand_binop (DImode, and_optab, a0,
+ gen_int_mode (GET_MODE_MASK (data_mode), DImode),
+ NULL_RTX, 1, OPTAB_WIDEN);
+
+ }
- /* Perform carry-less multiplication. */
+ /* Perform carry-less multiplication with polynomial. */
emit_insn (gen_aarch64_crypto_pmulldi (pmull_res, a0, t1));
+ if ((crc_size == 64) && (UINTVAL (polynomial) & 1))
+ {
+ /* Perform xor of pmull_res[127:64] with a0.
+ This is needed when the 65th bit of reflected polynomial is 1. */
+ rtx tmp = gen_reg_rtx (V2DImode);
+ emit_move_insn (tmp, gen_rtx_VEC_DUPLICATE (V2DImode, a0));
+ rtx xor_res = expand_binop (V2DImode, xor_optab,
+ gen_lowpart (V2DImode, pmull_res), tmp,
+ NULL_RTX, 1, OPTAB_DIRECT);
+ pmull_res = gen_lowpart (TImode, xor_res);
+ }
+
/* Perform a shift right by CRC_SIZE as an extraction of lane 1. */
machine_mode crc_vmode = aarch64_v128_mode (crc_mode).require ();
a0 = (crc_size > data_size ? gen_reg_rtx (crc_mode) : operands[0]);
diff --git a/gcc/config/aarch64/aarch64.md b/gcc/config/aarch64/aarch64.md
index 8d0e50db272..3e08d4dc3d1 100644
--- a/gcc/config/aarch64/aarch64.md
+++ b/gcc/config/aarch64/aarch64.md
@@ -5010,33 +5010,35 @@ (define_insn "aarch64_<crc_variant>"
)
;; Reversed CRC
-(define_expand "crc_rev<ALLI:mode><ALLX:mode>4"
+(define_expand "crc_rev<ALLI:mode><ALLI_2:mode>4"
[;; return value (calculated CRC)
- (match_operand:ALLX 0 "register_operand" "=r")
+ (match_operand:ALLI_2 0 "register_operand" "=r")
;; initial CRC
- (match_operand:ALLX 1 "register_operand" "r")
+ (match_operand:ALLI_2 1 "register_operand" "r")
;; data
(match_operand:ALLI 2 "register_operand" "r")
;; polynomial without leading 1
- (match_operand:ALLX 3 "const_int_operand")]
+ (match_operand:ALLI_2 3 "const_int_operand")]
""
{
/* If the polynomial is the same as the polynomial of crc32c* instruction,
put that instruction. crc32c uses iSCSI polynomial. */
if (TARGET_CRC32 && INTVAL (operands[3]) == 0x1EDC6F41
- && <ALLX:MODE>mode == SImode)
+ && <ALLI_2:MODE>mode == SImode
+ && <ALLI:MODE>mode != DImode)
emit_insn (gen_aarch64_crc32c<ALLI:crc_data_type> (operands[0],
operands[1],
operands[2]));
/* If the polynomial is the same as the polynomial of crc32* instruction,
put that instruction. crc32 uses HDLC etc. polynomial. */
else if (TARGET_CRC32 && INTVAL (operands[3]) == 0x04C11DB7
- && <ALLX:MODE>mode == SImode)
+ && <ALLI_2:MODE>mode == SImode
+ && <ALLI:MODE>mode != DImode)
emit_insn (gen_aarch64_crc32<ALLI:crc_data_type> (operands[0],
operands[1],
operands[2]));
- else if (TARGET_AES && <ALLI:sizen> <= <ALLX:sizen>)
- aarch64_expand_reversed_crc_using_pmull (<ALLX:MODE>mode,
+ else if (TARGET_AES && <ALLI:sizen> <= <ALLI_2:sizen>)
+ aarch64_expand_reversed_crc_using_pmull (<ALLI_2:MODE>mode,
<ALLI:MODE>mode,
operands);
else
@@ -5048,18 +5050,18 @@ (define_expand "crc_rev<ALLI:mode><ALLX:mode>4"
)
;; Bit-forward CRC
-(define_expand "crc<ALLI:mode><ALLX:mode>4"
+(define_expand "crc<ALLI:mode><ALLI_2:mode>4"
[;; return value (calculated CRC)
- (match_operand:ALLX 0 "register_operand" "=r")
+ (match_operand:ALLI_2 0 "register_operand" "=r")
;; initial CRC
- (match_operand:ALLX 1 "register_operand" "r")
+ (match_operand:ALLI_2 1 "register_operand" "r")
;; data
- (match_operand:ALLI 2 "register_operand" "r")
+ (match_operand:ALLI 2 "register_operand" "r")
;; polynomial without leading 1
- (match_operand:ALLX 3 "const_int_operand")]
- "TARGET_AES && <ALLI:sizen> <= <ALLX:sizen>"
+ (match_operand:ALLI_2 3 "const_int_operand")]
+ "TARGET_AES && <ALLI:sizen> <= <ALLI_2:sizen>"
{
- aarch64_expand_crc_using_pmull (<ALLX:MODE>mode, <ALLI:MODE>mode,
+ aarch64_expand_crc_using_pmull (<ALLI_2:MODE>mode, <ALLI:MODE>mode,
operands);
DONE;
}
diff --git a/gcc/config/aarch64/iterators.md b/gcc/config/aarch64/iterators.md
index f38a39fd6e3..ad5252fb8a3 100644
--- a/gcc/config/aarch64/iterators.md
+++ b/gcc/config/aarch64/iterators.md
@@ -47,6 +47,9 @@ (define_mode_iterator V4SF_ONLY [V4SF])
;; Iterator for all integer modes (up to 64-bit)
(define_mode_iterator ALLI [QI HI SI DI])
+;; Iterator for all integer modes (up to 64-bit) duplicated
+(define_mode_iterator ALLI_2 [QI HI SI DI])
+
;; Iterator for all integer modes (up to 128-bit)
(define_mode_iterator ALLI_TI [QI HI SI DI TI])
diff --git a/gcc/testsuite/gcc.target/aarch64/crc-34-pmul.c
b/gcc/testsuite/gcc.target/aarch64/crc-34-pmul.c
new file mode 100644
index 00000000000..374b81b5335
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/crc-34-pmul.c
@@ -0,0 +1,9 @@
+/* { dg-do run } */
+/* { dg-options "-march=armv8-a+crypto -O2 -fdump-rtl-dfinish -fdump-tree-crc
-fdisable-tree-phiopt2 -fdisable-tree-phiopt3" } */
+/* { dg-skip-if "" { *-*-* } { "-flto"} } */
+
+#include "../../gcc.dg/torture/crc-34.c"
+
+/* { dg-final { scan-tree-dump "calculates CRC!" "crc"} } */
+/* { dg-final { scan-tree-dump-times "Couldn't generate faster CRC code." 0
"crc"} } */
+/* { dg-final { scan-rtl-dump "pmull" "dfinish"} } */
diff --git a/gcc/testsuite/gcc.target/aarch64/crc-35-pmul.c
b/gcc/testsuite/gcc.target/aarch64/crc-35-pmul.c
new file mode 100644
index 00000000000..437356b9b9f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/crc-35-pmul.c
@@ -0,0 +1,9 @@
+/* { dg-do run } */
+/* { dg-options "-march=armv8-a+crypto -O2 -fdump-rtl-dfinish -fdump-tree-crc
-fdisable-tree-phiopt2 -fdisable-tree-phiopt3" } */
+/* { dg-skip-if "" { *-*-* } { "-flto"} } */
+
+#include "../../gcc.dg/torture/crc-35.c"
+
+/* { dg-final { scan-tree-dump "calculates CRC!" "crc"} } */
+/* { dg-final { scan-tree-dump-times "Couldn't generate faster CRC code." 0
"crc"} } */
+/* { dg-final { scan-rtl-dump "pmull" "dfinish"} } */
diff --git a/gcc/testsuite/gcc.target/aarch64/crc-36-pmul.c
b/gcc/testsuite/gcc.target/aarch64/crc-36-pmul.c
new file mode 100644
index 00000000000..a631c0a73cc
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/crc-36-pmul.c
@@ -0,0 +1,9 @@
+/* { dg-do run } */
+/* { dg-options "-march=armv8-a+crypto -O2 -fdump-rtl-dfinish -fdump-tree-crc
-fdisable-tree-phiopt2 -fdisable-tree-phiopt3" } */
+/* { dg-skip-if "" { *-*-* } { "-flto"} } */
+
+#include "../../gcc.dg/torture/crc-36.c"
+
+/* { dg-final { scan-tree-dump "calculates CRC!" "crc"} } */
+/* { dg-final { scan-tree-dump-times "Couldn't generate faster CRC code." 0
"crc"} } */
+/* { dg-final { scan-rtl-dump "pmull" "dfinish"} } */
diff --git a/gcc/testsuite/gcc.target/aarch64/crc-37-pmul.c
b/gcc/testsuite/gcc.target/aarch64/crc-37-pmul.c
new file mode 100644
index 00000000000..16b9e6c039d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/crc-37-pmul.c
@@ -0,0 +1,9 @@
+/* { dg-do run } */
+/* { dg-options "-march=armv8-a+crypto -O2 -fdump-rtl-dfinish -fdump-tree-crc
-fdisable-tree-phiopt2 -fdisable-tree-phiopt3" } */
+/* { dg-skip-if "" { *-*-* } { "-flto"} } */
+
+#include "../../gcc.dg/torture/crc-37.c"
+
+/* { dg-final { scan-tree-dump "calculates CRC!" "crc"} } */
+/* { dg-final { scan-tree-dump-times "Couldn't generate faster CRC code." 0
"crc"} } */
+/* { dg-final { scan-rtl-dump "pmull" "dfinish"} } */
diff --git a/gcc/testsuite/gcc.target/aarch64/crc-38-pmul.c
b/gcc/testsuite/gcc.target/aarch64/crc-38-pmul.c
new file mode 100644
index 00000000000..d447b49586d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/crc-38-pmul.c
@@ -0,0 +1,9 @@
+/* { dg-do run } */
+/* { dg-options "-march=armv8-a+crypto -O2 -fdump-rtl-dfinish -fdump-tree-crc
-fdisable-tree-phiopt2 -fdisable-tree-phiopt3" } */
+/* { dg-skip-if "" { *-*-* } { "-flto"} } */
+
+#include "../../gcc.dg/torture/crc-38.c"
+
+/* { dg-final { scan-tree-dump "calculates CRC!" "crc"} } */
+/* { dg-final { scan-tree-dump-times "Couldn't generate faster CRC code." 0
"crc"} } */
+/* { dg-final { scan-rtl-dump "pmull" "dfinish"} } */
diff --git a/gcc/testsuite/gcc.target/aarch64/crc-39-pmul.c
b/gcc/testsuite/gcc.target/aarch64/crc-39-pmul.c
new file mode 100644
index 00000000000..9cf59083e47
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/crc-39-pmul.c
@@ -0,0 +1,9 @@
+/* { dg-do run } */
+/* { dg-options "-march=armv8-a+crypto -O2 -fdump-rtl-dfinish -fdump-tree-crc
-fdisable-tree-phiopt2 -fdisable-tree-phiopt3" } */
+/* { dg-skip-if "" { *-*-* } { "-flto"} } */
+
+#include "../../gcc.dg/torture/crc-39.c"
+
+/* { dg-final { scan-tree-dump "calculates CRC!" "crc"} } */
+/* { dg-final { scan-tree-dump-times "Couldn't generate faster CRC code." 0
"crc"} } */
+/* { dg-final { scan-rtl-dump "pmull" "dfinish"} } */
diff --git a/gcc/testsuite/gcc.target/aarch64/crc-40-pmul.c
b/gcc/testsuite/gcc.target/aarch64/crc-40-pmul.c
new file mode 100644
index 00000000000..72d806469a4
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/crc-40-pmul.c
@@ -0,0 +1,9 @@
+/* { dg-do run } */
+/* { dg-options "-march=armv8-a+crypto -O2 -fdump-rtl-dfinish -fdump-tree-crc
-fdisable-tree-phiopt2 -fdisable-tree-phiopt3" } */
+/* { dg-skip-if "" { *-*-* } { "-flto"} } */
+
+#include "../../gcc.dg/torture/crc-40.c"
+
+/* { dg-final { scan-tree-dump "calculates CRC!" "crc"} } */
+/* { dg-final { scan-tree-dump-times "Couldn't generate faster CRC code." 0
"crc"} } */
+/* { dg-final { scan-rtl-dump "pmull" "dfinish"} } */
diff --git a/gcc/testsuite/gcc.target/aarch64/crc-41-pmul.c
b/gcc/testsuite/gcc.target/aarch64/crc-41-pmul.c
new file mode 100644
index 00000000000..e526651474d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/crc-41-pmul.c
@@ -0,0 +1,9 @@
+/* { dg-do run } */
+/* { dg-options "-march=armv8-a+crypto -O2 -fdump-rtl-dfinish -fdump-tree-crc
-fdisable-tree-phiopt2 -fdisable-tree-phiopt3" } */
+/* { dg-skip-if "" { *-*-* } { "-flto"} } */
+
+#include "../../gcc.dg/torture/crc-41.c"
+
+/* { dg-final { scan-tree-dump "calculates CRC!" "crc"} } */
+/* { dg-final { scan-tree-dump-times "Couldn't generate faster CRC code." 0
"crc"} } */
+/* { dg-final { scan-rtl-dump "pmull" "dfinish"} } */
--
2.55.0