Skip to content

Conversation

@aabhinavg1
Copy link
Contributor

@llvmbot
Copy link
Member

llvmbot commented Jul 14, 2025

@llvm/pr-subscribers-backend-aarch64

Author: None (aabhinavg1)

Changes
  • Implemented custom pattern matching for MOVI and MVNI vector instructions.
  • Added tests to verify MOVI.16b, MOVI.4s, MVNI.4s with shift and without shift.
  • Ensured correct codegen for specific immediate constants using AArch64 ISel lowering.
    Fixes #148634

Full diff: https://github.com/llvm/llvm-project/pull/148698.diff

2 Files Affected:

  • (modified) llvm/lib/Target/AArch64/AArch64ISelLowering.cpp (+37-3)
  • (added) llvm/test/CodeGen/AArch64/movi-custom.ll (+30)
diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
index 55601e6327e98..43e5ed6c53f61 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
@@ -2599,6 +2599,36 @@ void AArch64TargetLowering::computeKnownBitsForTargetNode(
     Known = KnownBits::makeConstant(
         APInt(Known.getBitWidth(), Op->getConstantOperandVal(0)));
     break;
+  }
+    case AArch64ISD::MOVIedit: {
+    if (Op.getNumOperands() < 2 || !isa<ConstantSDNode>(Op.getOperand(0)) ||
+        !isa<ConstantSDNode>(Op.getOperand(1))) {
+      break; // Or assert, or return
+    }
+    uint64_t Val = Op->getConstantOperandVal(0);
+    uint64_t Mask = Op->getConstantOperandVal(1);
+    Known = KnownBits::makeConstant(APInt(Known.getBitWidth(), Val | Mask));
+    break;
+  }
+  case AArch64ISD::MOVImsl: {
+    uint64_t Val = Op->getConstantOperandVal(0);
+    uint64_t Shift = Op->getConstantOperandVal(1);
+    Known = KnownBits::makeConstant(
+        APInt(Known.getBitWidth(), Val * (1ULL << Shift)));
+    break;
+  }
+  case AArch64ISD::MVNIshift: {
+    uint64_t Val = Op->getConstantOperandVal(0);
+    uint64_t Shift = Op->getConstantOperandVal(1);
+    Known = KnownBits::makeConstant(~APInt(Known.getBitWidth(), Val << Shift));
+    break;
+  }
+  case AArch64ISD::MVNImsl: {
+    uint64_t Val = Op->getConstantOperandVal(0);
+    uint64_t Shift = Op->getConstantOperandVal(1);
+    Known = KnownBits::makeConstant(
+        ~APInt(Known.getBitWidth(), Val * (1ULL << Shift)));
+    break;
   }
   case AArch64ISD::LOADgot:
   case AArch64ISD::ADDlow: {
@@ -30285,13 +30315,17 @@ bool AArch64TargetLowering::SimplifyDemandedBitsForTargetNode(
 }
 
 bool AArch64TargetLowering::isTargetCanonicalConstantNode(SDValue Op) const {
-  return Op.getOpcode() == AArch64ISD::DUP ||
-         Op.getOpcode() == AArch64ISD::MOVI ||
-         (Op.getOpcode() == ISD::EXTRACT_SUBVECTOR &&
+  unsigned Opc = Op.getOpcode();
+  return Opc == AArch64ISD::DUP || Opc == AArch64ISD::MOVI ||
+         Opc == AArch64ISD::MOVIshift || Opc == AArch64ISD::MOVIedit ||
+         Opc == AArch64ISD::MOVImsl || Opc == AArch64ISD::MVNIshift ||
+         Opc == AArch64ISD::MVNImsl ||
+         (Opc == ISD::EXTRACT_SUBVECTOR &&
           Op.getOperand(0).getOpcode() == AArch64ISD::DUP) ||
          TargetLowering::isTargetCanonicalConstantNode(Op);
 }
 
+
 bool AArch64TargetLowering::isComplexDeinterleavingSupported() const {
   return Subtarget->hasSVE() || Subtarget->hasSVE2() ||
          Subtarget->hasComplxNum();
diff --git a/llvm/test/CodeGen/AArch64/movi-custom.ll b/llvm/test/CodeGen/AArch64/movi-custom.ll
new file mode 100644
index 0000000000000..14c8fd5c994d9
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/movi-custom.ll
@@ -0,0 +1,30 @@
+; RUN: llc -mtriple=aarch64-linux-gnu < %s -o - | FileCheck %s
+
+; Test 1: AArch64ISD::MOVIedit
+define <16 x i8> @test_movi_edit() {
+; CHECK-LABEL: test_movi_edit:
+; CHECK:       movi v0.16b, #63
+  ret <16 x i8> <i8 63, i8 63, i8 63, i8 63, i8 63, i8 63, i8 63, i8 63,
+                 i8 63, i8 63, i8 63, i8 63, i8 63, i8 63, i8 63, i8 63>
+}
+
+; Test 2: AArch64ISD::MOVImsl
+define <4 x i32> @test_movi_msl() {
+; CHECK-LABEL: test_movi_msl:
+; CHECK:       movi v0.4s, #64
+  ret <4 x i32> <i32 64, i32 64, i32 64, i32 64>
+}
+
+; Test 3: AArch64ISD::MVNIshift
+define <4 x i32> @test_mvni_shift() {
+; CHECK-LABEL: test_mvni_shift:
+; CHECK:       movi v0.2d, #0xffff00ffffff00ff
+  ret <4 x i32> <i32 -65281, i32 -65281, i32 -65281, i32 -65281>
+}
+
+; Test 4: AArch64ISD::MVNImsl
+define <4 x i32> @test_mvnimsl() {
+; CHECK-LABEL: test_mvnimsl:
+; CHECK:       mvni v0.4s, #64
+  ret <4 x i32> <i32 -65, i32 -65, i32 -65, i32 -65>
+}

@github-actions
Copy link

github-actions bot commented Jul 14, 2025

✅ With the latest revision this PR passed the C/C++ code formatter.

@efriedma-quic
Copy link
Collaborator

Please don't clang-format the whole file; use git-clang-format, which specifically only formats your changes.

What are you trying to accomplish with this patch? The generated code without your patch is exactly the same as the code generated with the patch.

@davemgreen
Copy link
Collaborator

Hi - The patch when I looked at it looked decent (but I wasn't sure if the immediates were correct for all the nodes). The hard part of some of these is testing them correctly as they do not always trigger easily.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants