[llvm] [AArch64] Handle XAR with v1i64 operand types (PR #141754)

David Green via llvm-commits llvm-commits at lists.llvm.org
Thu May 29 02:13:34 PDT 2025


https://github.com/davemgreen updated https://github.com/llvm/llvm-project/pull/141754

>From 478a7f955617e42d8c486075382114c7e0155b9c Mon Sep 17 00:00:00 2001
From: David Green <david.green at arm.com>
Date: Wed, 28 May 2025 13:41:20 +0100
Subject: [PATCH 1/2] [AArch64] Handle XAR with v1i64 operand types

When converting ROTR(XOR(a, b)) to XAR(a, b), or ROTR(a, a) to XAR(a, zero) we
were not handling v1i64 types, meaning illegal copies get generated. This
addresses that by generating insert_subreg and extract_subreg for v1i64 types
to keep the values with the correct types.

Fixes #141746
---
 .../Target/AArch64/AArch64ISelDAGToDAG.cpp    | 28 ++++++++++++-
 llvm/test/CodeGen/AArch64/xar.ll              | 39 +++++++++++++++++++
 2 files changed, 65 insertions(+), 2 deletions(-)

diff --git a/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp b/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp
index 2eb8c6008db0f..0b7a810fd4747 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp
@@ -4637,15 +4637,39 @@ bool AArch64DAGToDAGISel::trySelectXAR(SDNode *N) {
 
   if (!IsXOROperand) {
     SDValue Zero = CurDAG->getTargetConstant(0, DL, MVT::i64);
-    SDNode *MOV = CurDAG->getMachineNode(AArch64::MOVIv2d_ns, DL, VT, Zero);
+    SDNode *MOV =
+        CurDAG->getMachineNode(AArch64::MOVIv2d_ns, DL, MVT::v2i64, Zero);
     SDValue MOVIV = SDValue(MOV, 0);
     R1 = N1->getOperand(0);
     R2 = MOVIV;
   }
 
+  // If the input is a v1i64, widen to a v2i64 to use XAR.
+  assert((VT == MVT::v1i64 || VT == MVT::v2i64) && "Unexpected XAR type!");
+  if (VT == MVT::v1i64) {
+    EVT SVT = MVT::v2i64;
+    SDValue Undef =
+        SDValue(CurDAG->getMachineNode(AArch64::IMPLICIT_DEF, DL, SVT), 0);
+    SDValue DSub = CurDAG->getTargetConstant(AArch64::dsub, DL, MVT::i32);
+    R1 = SDValue(CurDAG->getMachineNode(AArch64::INSERT_SUBREG, DL, SVT, Undef,
+                                        R1, DSub),
+                 0);
+    if (R2.getValueType() == MVT::v1i64)
+      R2 = SDValue(CurDAG->getMachineNode(AArch64::INSERT_SUBREG, DL, SVT,
+                                          Undef, R2, DSub),
+                   0);
+  }
+
   SDValue Ops[] = {R1, R2, Imm};
-  CurDAG->SelectNodeTo(N, AArch64::XAR, N0.getValueType(), Ops);
+  SDNode *XAR =
+      CurDAG->getMachineNode(AArch64::XAR, DL, R1.getValueType(), Ops);
 
+  if (VT == MVT::v1i64) {
+    SDValue DSub = CurDAG->getTargetConstant(AArch64::dsub, DL, MVT::i32);
+    XAR = CurDAG->getMachineNode(AArch64::EXTRACT_SUBREG, DL, VT,
+                                 SDValue(XAR, 0), DSub);
+  }
+  ReplaceNode(N, XAR);
   return true;
 }
 
diff --git a/llvm/test/CodeGen/AArch64/xar.ll b/llvm/test/CodeGen/AArch64/xar.ll
index e15cb6a696aa5..d682f4f4a1bfb 100644
--- a/llvm/test/CodeGen/AArch64/xar.ll
+++ b/llvm/test/CodeGen/AArch64/xar.ll
@@ -19,6 +19,26 @@ define <2 x i64> @xar(<2 x i64> %x, <2 x i64> %y) {
     ret <2 x i64> %b
 }
 
+define <1 x i64> @xar_v1i64(<1 x i64> %a, <1 x i64> %b) {
+; SHA3-LABEL: xar_v1i64:
+; SHA3:       // %bb.0:
+; SHA3-NEXT:    // kill: def $d0 killed $d0 def $q0
+; SHA3-NEXT:    // kill: def $d1 killed $d1 def $q1
+; SHA3-NEXT:    xar v0.2d, v0.2d, v1.2d, #63
+; SHA3-NEXT:    // kill: def $d0 killed $d0 killed $q0
+; SHA3-NEXT:    ret
+;
+; NOSHA3-LABEL: xar_v1i64:
+; NOSHA3:       // %bb.0:
+; NOSHA3-NEXT:    eor v1.8b, v0.8b, v1.8b
+; NOSHA3-NEXT:    shl d0, d1, #1
+; NOSHA3-NEXT:    usra d0, d1, #63
+; NOSHA3-NEXT:    ret
+  %v.val = xor <1 x i64> %a, %b
+  %fshl = tail call <1 x i64> @llvm.fshl.v1i64(<1 x i64> %v.val, <1 x i64> %v.val, <1 x i64> splat (i64 1))
+  ret <1 x i64> %fshl
+}
+
 define <2 x i64> @xar_instead_of_or1(<2 x i64> %r) {
 ; SHA3-LABEL: xar_instead_of_or1:
 ; SHA3:       // %bb.0: // %entry
@@ -37,6 +57,25 @@ entry:
   ret <2 x i64> %or
 }
 
+define <1 x i64> @xar_instead_of_or_v1i64(<1 x i64> %v.val) {
+; SHA3-LABEL: xar_instead_of_or_v1i64:
+; SHA3:       // %bb.0:
+; SHA3-NEXT:    movi v1.2d, #0000000000000000
+; SHA3-NEXT:    // kill: def $d0 killed $d0 def $q0
+; SHA3-NEXT:    xar v0.2d, v0.2d, v1.2d, #63
+; SHA3-NEXT:    // kill: def $d0 killed $d0 killed $q0
+; SHA3-NEXT:    ret
+;
+; NOSHA3-LABEL: xar_instead_of_or_v1i64:
+; NOSHA3:       // %bb.0:
+; NOSHA3-NEXT:    shl d1, d0, #1
+; NOSHA3-NEXT:    usra d1, d0, #63
+; NOSHA3-NEXT:    fmov d0, d1
+; NOSHA3-NEXT:    ret
+  %fshl = tail call <1 x i64> @llvm.fshl.v1i64(<1 x i64> %v.val, <1 x i64> %v.val, <1 x i64> splat (i64 1))
+  ret <1 x i64> %fshl
+}
+
 define <4 x i32> @xar_instead_of_or2(<4 x i32> %r) {
 ; SHA3-LABEL: xar_instead_of_or2:
 ; SHA3:       // %bb.0: // %entry

>From 38aa26bb4a4dac3991b6e0f6c6f14f61b5d75645 Mon Sep 17 00:00:00 2001
From: David Green <dmg862 at gmail.com>
Date: Thu, 29 May 2025 10:13:23 +0100
Subject: [PATCH 2/2] Update llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp

---
 llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp b/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp
index 0b7a810fd4747..34f6db9374cb5 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp
@@ -4661,8 +4661,7 @@ bool AArch64DAGToDAGISel::trySelectXAR(SDNode *N) {
   }
 
   SDValue Ops[] = {R1, R2, Imm};
-  SDNode *XAR =
-      CurDAG->getMachineNode(AArch64::XAR, DL, R1.getValueType(), Ops);
+  SDNode *XAR = CurDAG->getMachineNode(AArch64::XAR, DL, MVT::v2i64, Ops);
 
   if (VT == MVT::v1i64) {
     SDValue DSub = CurDAG->getTargetConstant(AArch64::dsub, DL, MVT::i32);



More information about the llvm-commits mailing list