[llvm] 528e6f9 - [AArch64] Avoid creating a new generic constant in SelectSMETileSlice (#203344)

via llvm-commits llvm-commits at lists.llvm.org
Fri Jun 12 09:46:28 PDT 2026


Author: Benjamin Maxwell
Date: 2026-06-12T17:46:23+01:00
New Revision: 528e6f9a030c4b3bf760807c22c98f17fb582f5f

URL: https://github.com/llvm/llvm-project/commit/528e6f9a030c4b3bf760807c22c98f17fb582f5f
DIFF: https://github.com/llvm/llvm-project/commit/528e6f9a030c4b3bf760807c22c98f17fb582f5f.diff

LOG: [AArch64] Avoid creating a new generic constant in SelectSMETileSlice (#203344)

This was creating a new ISD::Constant node during instruction selection,
which may also need lowering (e.g., to a `mov gpr, wzr`). The issue with
this is the new constant node will not end up on the instruction
selection worklist, as the complex pattern executes after the worklist
has been prepared. This means the constant will lower directly to an
immediate. This issue was hidden in some cases by `getConstant()`
returning a pre-existing `ISD::Constant` node already within the
instruction selection worklist.

This patch works around this by directly emitting a `CopyFromReg WZR`
within SelectSMETileSlice, which does not need further instruction
selection.

Fixes #203295

Added: 
    

Modified: 
    llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp
    llvm/test/CodeGen/AArch64/sme-intrinsics-mova-insert.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp b/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp
index ade5b9e0e6e70..ade160de983b1 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp
@@ -5069,6 +5069,14 @@ bool AArch64DAGToDAGISel::trySelectXAR(SDNode *N) {
   return true;
 }
 
+/// Returns a copy from WZR or XZR. This can be used during instruction
+/// selection (it does not require any further selection/legalization).
+static SDValue getZeroRegister(SelectionDAG &DAG, SDLoc DL, EVT VT) {
+  assert(VT == MVT::i32 || VT == MVT::i64);
+  return DAG.getCopyFromReg(DAG.getEntryNode(), DL,
+                            VT == MVT::i32 ? AArch64::WZR : AArch64::XZR, VT);
+}
+
 void AArch64DAGToDAGISel::Select(SDNode *Node) {
   // If we have a custom node, we already have selected!
   if (Node->isMachineOpcode()) {
@@ -5152,18 +5160,9 @@ void AArch64DAGToDAGISel::Select(SDNode *Node) {
     // Materialize zero constants as copies from WZR/XZR.  This allows
     // the coalescer to propagate these into other instructions.
     ConstantSDNode *ConstNode = cast<ConstantSDNode>(Node);
-    if (ConstNode->isZero()) {
-      if (VT == MVT::i32) {
-        SDValue New = CurDAG->getCopyFromReg(
-            CurDAG->getEntryNode(), SDLoc(Node), AArch64::WZR, MVT::i32);
-        ReplaceNode(Node, New.getNode());
-        return;
-      } else if (VT == MVT::i64) {
-        SDValue New = CurDAG->getCopyFromReg(
-            CurDAG->getEntryNode(), SDLoc(Node), AArch64::XZR, MVT::i64);
-        ReplaceNode(Node, New.getNode());
-        return;
-      }
+    if (ConstNode->isZero() && (VT == MVT::i32 || VT == MVT::i64)) {
+      ReplaceNode(Node, getZeroRegister(*CurDAG, SDLoc(Node), VT).getNode());
+      return;
     }
     break;
   }
@@ -8019,7 +8018,7 @@ bool AArch64DAGToDAGISel::SelectSMETileSlice(SDValue N, unsigned MaxSize,
   };
 
   if (SDValue C = MatchConstantOffset(N)) {
-    Base = CurDAG->getConstant(0, SDLoc(N), MVT::i32);
+    Base = getZeroRegister(*CurDAG, SDLoc(N), MVT::i32);
     Offset = C;
     return true;
   }

diff  --git a/llvm/test/CodeGen/AArch64/sme-intrinsics-mova-insert.ll b/llvm/test/CodeGen/AArch64/sme-intrinsics-mova-insert.ll
index 9c5becf6ffbf2..3d9065bda9c26 100644
--- a/llvm/test/CodeGen/AArch64/sme-intrinsics-mova-insert.ll
+++ b/llvm/test/CodeGen/AArch64/sme-intrinsics-mova-insert.ll
@@ -486,6 +486,17 @@ define void @test_add_with_disjoint_or(i64 %idx, <vscale x 4 x i1> %pg) {
   ret void
 }
 
+; Test we materialize the zero register base within a GPR when we only have an immediate slice offset.
+define void @test_imm_offset_with_zero_register_base(<vscale x 4 x i1> %pg, <vscale x 4 x i32> %vec) {
+; CHECK-LABEL: test_imm_offset_with_zero_register_base:
+; CHECK:       // %bb.0:
+; CHECK-NEXT:    mov w12, wzr
+; CHECK-NEXT:    mov za0h.s[w12, 1], p0/m, z0.s
+; CHECK-NEXT:    ret
+  call void @llvm.aarch64.sme.write.horiz.nxv4i32(i32 0, i32 1, <vscale x 4 x i1> %pg, <vscale x 4 x i32> %vec)
+  ret void
+}
+
 declare void @llvm.aarch64.sme.write.horiz.nxv16i8(i32, i32, <vscale x 16 x i1>, <vscale x 16 x i8>)
 declare void @llvm.aarch64.sme.write.horiz.nxv8i16(i32, i32, <vscale x 8 x i1>, <vscale x 8 x i16>)
 declare void @llvm.aarch64.sme.write.horiz.nxv8f16(i32, i32, <vscale x 8 x i1>, <vscale x 8 x half>)


        


More information about the llvm-commits mailing list