From 7a71dbb9484b6fe47fccd793603a6af5c1dece47 Mon Sep 17 00:00:00 2001
From: Sergey Fedorov <barracuda@macos-powerpc.org>
Date: Sat, 22 Nov 2025 22:16:36 +0700
Subject: [PATCH 6/7] AArch64: Add FuseCryptoEOR fusion rules

Cherry-picks from https://github.com/llvm/llvm-project/commit/28d6a4ac9a91a6f17bfa5e900bd73b829bb00585
---
 llvm/lib/Target/AArch64/AArch64.td            |  4 ++++
 .../lib/Target/AArch64/AArch64MacroFusion.cpp | 23 +++++++++++++++++++
 llvm/lib/Target/AArch64/AArch64Subtarget.h    |  2 ++
 3 files changed, 29 insertions(+)

diff --git llvm/lib/Target/AArch64/AArch64.td llvm/lib/Target/AArch64/AArch64.td
index 8df92103f70..821baba7e8d 100644
--- llvm/lib/Target/AArch64/AArch64.td
+++ llvm/lib/Target/AArch64/AArch64.td
@@ -156,6 +156,10 @@ def FeatureFuseAES : SubtargetFeature<
     "fuse-aes", "HasFuseAES", "true",
     "CPU fuses AES crypto operations">;
 
+def FeatureFuseCryptoEOR : SubtargetFeature<
+    "fuse-crypto-eor", "HasFuseCryptoEOR", "true",
+    "CPU fuses AES/PMULL and EOR operations">;
+
 def FeatureFuseCCSelect : SubtargetFeature<
     "fuse-csel", "HasFuseCCSelect", "true",
     "CPU fuses conditional select operations">;
diff --git llvm/lib/Target/AArch64/AArch64MacroFusion.cpp llvm/lib/Target/AArch64/AArch64MacroFusion.cpp
index bc0168e783b..3fa565d254f 100644
--- llvm/lib/Target/AArch64/AArch64MacroFusion.cpp
+++ llvm/lib/Target/AArch64/AArch64MacroFusion.cpp
@@ -132,6 +132,27 @@ static bool isAESPair(const MachineInstr *FirstMI,
   return false;
 }
 
+/// AESE/AESD/PMULL + EOR.
+static bool isCryptoEORPair(const MachineInstr *FirstMI,
+                           const MachineInstr &SecondMI) {
+  unsigned SecondOpcode = SecondMI.getOpcode();
+
+  if (SecondOpcode != AArch64::EORv16i8)
+    return false;
+
+  switch (FirstMI->getOpcode()) {
+  case AArch64::INSTRUCTION_LIST_END:
+  case AArch64::AESErr:
+  case AArch64::AESDrr:
+  case AArch64::PMULLv16i8:
+  case AArch64::PMULLv8i8:
+  case AArch64::PMULLv1i64:
+  case AArch64::PMULLv2i64:
+    return true;
+  }
+  return false;
+}
+
 // Fuse literal generation.
 static bool isLiteralsPair(const MachineInstr *FirstMI,
                            const MachineInstr &SecondMI) {
@@ -270,6 +291,8 @@ static bool shouldScheduleAdjacent(const TargetInstrInfo &TII,
     return true;
   if (ST.hasFuseAES() && isAESPair(FirstMI, SecondMI))
     return true;
+  if (ST.hasFuseCryptoEOR() && isCryptoEORPair(FirstMI, SecondMI))
+    return true;
   if (ST.hasFuseLiterals() && isLiteralsPair(FirstMI, SecondMI))
     return true;
   if (ST.hasFuseAddress() && isAddressLdStPair(FirstMI, SecondMI))
diff --git llvm/lib/Target/AArch64/AArch64Subtarget.h llvm/lib/Target/AArch64/AArch64Subtarget.h
index fb272f1c466..e0737eb8730 100644
--- llvm/lib/Target/AArch64/AArch64Subtarget.h
+++ llvm/lib/Target/AArch64/AArch64Subtarget.h
@@ -128,6 +128,7 @@ protected:
   bool HasArithmeticCbzFusion = false;
   bool HasFuseAddress = false;
   bool HasFuseAES = false;
+  bool HasFuseCryptoEOR = false;
   bool HasFuseCCSelect = false;
   bool HasFuseLiterals = false;
   bool DisableLatencySchedHeuristic = false;
@@ -265,6 +266,7 @@ public:
   bool hasArithmeticCbzFusion() const { return HasArithmeticCbzFusion; }
   bool hasFuseAddress() const { return HasFuseAddress; }
   bool hasFuseAES() const { return HasFuseAES; }
+  bool hasFuseCryptoEOR() const { return HasFuseCryptoEOR; }
   bool hasFuseCCSelect() const { return HasFuseCCSelect; }
   bool hasFuseLiterals() const { return HasFuseLiterals; }
 
