diff --git a/gcc/config/aarch64/aarch64-simd.md b/gcc/config/aarch64/aarch64-simd.md
index b725deb74ce830f4e5fe88fe352c296a30acac5a..48332ebd58046e5a8c8802701195da0a3fc8c776 100644
--- a/gcc/config/aarch64/aarch64-simd.md
+++ b/gcc/config/aarch64/aarch64-simd.md
@@ -5794,6 +5794,29 @@
   [(set_attr "type" "crypto_aese")]
 )
 
+(define_insn "*aarch64_crypto_aes<aes_op>v16qi_xor_combine"
+  [(set (match_operand:V16QI 0 "register_operand" "=w")
+	(unspec:V16QI [(xor:V16QI
+			(match_operand:V16QI 1 "register_operand" "%0")
+			(match_operand:V16QI 2 "register_operand" "w"))
+		       (match_operand:V16QI 3 "aarch64_simd_imm_zero" "")]
+		       CRYPTO_AES))]
+  "TARGET_SIMD && TARGET_AES"
+  "aes<aes_op>\\t%0.16b, %2.16b"
+  [(set_attr "type" "crypto_aese")]
+)
+
+(define_insn "*aarch64_crypto_aes<aes_op>v16qi_xor_combine"
+  [(set (match_operand:V16QI 0 "register_operand" "=w")
+	(unspec:V16QI [(match_operand:V16QI 3 "aarch64_simd_imm_zero" "")
+	(xor:V16QI (match_operand:V16QI 1 "register_operand" "%0")
+		   (match_operand:V16QI 2 "register_operand" "w"))]
+	CRYPTO_AES))]
+  "TARGET_SIMD && TARGET_AES"
+  "aes<aes_op>\\t%0.16b, %2.16b"
+  [(set_attr "type" "crypto_aese")]
+)
+
 ;; When AES/AESMC fusion is enabled we want the register allocation to
 ;; look like:
 ;;    AESE Vn, _
diff --git a/gcc/testsuite/gcc.target/aarch64/aes_xor_combine.c b/gcc/testsuite/gcc.target/aarch64/aes_xor_combine.c
new file mode 100644
index 0000000000000000000000000000000000000000..833e9b3073bdbc4d17c78327974b5106fb3f8663
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/aes_xor_combine.c
@@ -0,0 +1,70 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -mcpu=cortex-a55+crypto" } */
+#include <arm_neon.h>
+
+#define AESE(r, v, key) (r = vaeseq_u8 ((v), (key)));
+#define AESD(r, v, key) (r = vaesdq_u8 ((v), (key)));
+
+const uint8x16_t zero = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+
+uint8x16_t foo0 (uint8x16_t a, uint8x16_t b)
+{
+  uint8x16_t dummy;
+  AESE(dummy, a ^ b, zero);
+  return dummy;
+}
+
+uint8x16_t foo1 (uint8x16_t a, uint8x16_t b)
+{
+  uint8x16_t dummy;
+  AESE(dummy, a ^ b, zero);
+  AESE(dummy, dummy ^ a, zero);
+  return dummy;
+}
+
+uint8x16_t bar0 (uint8x16_t a, uint8x16_t b)
+{
+  uint8x16_t dummy;
+  AESE(dummy, zero, a ^ b);
+  return dummy;
+}
+
+uint8x16_t bar1 (uint8x16_t a, uint8x16_t b)
+{
+  uint8x16_t dummy;
+  AESE(dummy, zero, a ^ b);
+  AESE(dummy, zero, b ^ dummy);
+  return dummy;
+}
+
+uint8x16_t foo2 (uint8x16_t a, uint8x16_t b)
+{
+  uint8x16_t dummy;
+  AESD(dummy, a ^ b, zero);
+  return dummy;
+}
+
+uint8x16_t foo3 (uint8x16_t a, uint8x16_t b)
+{
+  uint8x16_t dummy;
+  AESD(dummy, a ^ b, zero);
+  AESD(dummy, dummy ^ a, zero);
+  return dummy;
+}
+
+uint8x16_t bar2 (uint8x16_t a, uint8x16_t b)
+{
+  uint8x16_t dummy;
+  AESD(dummy, zero, a ^ b);
+  return dummy;
+}
+
+uint8x16_t bar3 (uint8x16_t a, uint8x16_t b)
+{
+  uint8x16_t dummy;
+  AESD(dummy, zero, a ^ b);
+  AESD(dummy, zero, b ^ dummy);
+  return dummy;
+}
+/* { dg-final { scan-assembler-not "eor" } } */
+/* { dg-final { scan-assembler-not "mov" } } */
