[llvm] [AArch64] Sink NOT to be fold into BIC/ORN/EON (PR #176194)

Piotr Fusik via llvm-commits llvm-commits at lists.llvm.org
Mon Mar 2 02:54:03 PST 2026


https://github.com/pfusik updated https://github.com/llvm/llvm-project/pull/176194

>From d64093835ee351bd9a6b0726dda73bb307a06e77 Mon Sep 17 00:00:00 2001
From: Piotr Fusik <p.fusik at samsung.com>
Date: Thu, 15 Jan 2026 15:34:49 +0100
Subject: [PATCH 1/4] [Aarch64][test] Sink NOT to be fold into BIC/ORN/EON

---
 .../CodeGen/AArch64/logical-op-with-not.ll    | 396 +++++++++++
 .../AArch64/neon-bitwise-instructions.ll      | 664 ++++++++++++++++++
 2 files changed, 1060 insertions(+)

diff --git a/llvm/test/CodeGen/AArch64/logical-op-with-not.ll b/llvm/test/CodeGen/AArch64/logical-op-with-not.ll
index 3c4f06026a3cf..8db4ab6c8c4e9 100644
--- a/llvm/test/CodeGen/AArch64/logical-op-with-not.ll
+++ b/llvm/test/CodeGen/AArch64/logical-op-with-not.ll
@@ -320,3 +320,399 @@ define i64 @mvn_ror_i64(i64 %0) {
   %5 = xor i64 %4, -1
   ret i64 %5
 }
+
+define void @array_and_not_i8(ptr %a, i8 %m) {
+; CHECK-LABEL: array_and_not_i8:
+; CHECK:       // %bb.0: // %entry
+; CHECK-NEXT:    mov x8, xzr
+; CHECK-NEXT:    mvn w9, w1
+; CHECK-NEXT:  .LBB26_1: // %for.body
+; CHECK-NEXT:    // =>This Inner Loop Header: Depth=1
+; CHECK-NEXT:    ldrb w10, [x0, x8]
+; CHECK-NEXT:    and w10, w10, w9
+; CHECK-NEXT:    strb w10, [x0, x8]
+; CHECK-NEXT:    add x8, x8, #1
+; CHECK-NEXT:    cmp x8, #16
+; CHECK-NEXT:    b.ne .LBB26_1
+; CHECK-NEXT:  // %bb.2: // %for.cond.cleanup
+; CHECK-NEXT:    ret
+entry:
+  %not = xor i8 %m, -1
+  br label %for.body
+
+for.cond.cleanup:
+  ret void
+
+for.body:
+  %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ]
+  %arrayidx = getelementptr inbounds nuw i8, ptr %a, i64 %indvars.iv
+  %load = load i8, ptr %arrayidx, align 1
+  %and = and i8 %load, %not
+  store i8 %and, ptr %arrayidx, align 1
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  %exitcond.not = icmp eq i64 %indvars.iv.next, 16
+  br i1 %exitcond.not, label %for.cond.cleanup, label %for.body
+}
+
+define void @array_and_not_i16(ptr %a, i16 %m) {
+; CHECK-LABEL: array_and_not_i16:
+; CHECK:       // %bb.0: // %entry
+; CHECK-NEXT:    mov x8, xzr
+; CHECK-NEXT:    mvn w9, w1
+; CHECK-NEXT:  .LBB27_1: // %for.body
+; CHECK-NEXT:    // =>This Inner Loop Header: Depth=1
+; CHECK-NEXT:    ldrh w10, [x0, x8]
+; CHECK-NEXT:    and w10, w10, w9
+; CHECK-NEXT:    strh w10, [x0, x8]
+; CHECK-NEXT:    add x8, x8, #2
+; CHECK-NEXT:    cmp x8, #32
+; CHECK-NEXT:    b.ne .LBB27_1
+; CHECK-NEXT:  // %bb.2: // %for.cond.cleanup
+; CHECK-NEXT:    ret
+entry:
+  %not = xor i16 %m, -1
+  br label %for.body
+
+for.cond.cleanup:
+  ret void
+
+for.body:
+  %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ]
+  %arrayidx = getelementptr inbounds nuw i16, ptr %a, i64 %indvars.iv
+  %load = load i16, ptr %arrayidx, align 2
+  %and = and i16 %load, %not
+  store i16 %and, ptr %arrayidx, align 2
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  %exitcond.not = icmp eq i64 %indvars.iv.next, 16
+  br i1 %exitcond.not, label %for.cond.cleanup, label %for.body
+}
+
+define void @array_and_not_i32(ptr %a, i32 %m) {
+; CHECK-LABEL: array_and_not_i32:
+; CHECK:       // %bb.0: // %entry
+; CHECK-NEXT:    mov x8, xzr
+; CHECK-NEXT:    mvn w9, w1
+; CHECK-NEXT:  .LBB28_1: // %for.body
+; CHECK-NEXT:    // =>This Inner Loop Header: Depth=1
+; CHECK-NEXT:    ldr w10, [x0, x8]
+; CHECK-NEXT:    and w10, w10, w9
+; CHECK-NEXT:    str w10, [x0, x8]
+; CHECK-NEXT:    add x8, x8, #4
+; CHECK-NEXT:    cmp x8, #64
+; CHECK-NEXT:    b.ne .LBB28_1
+; CHECK-NEXT:  // %bb.2: // %for.cond.cleanup
+; CHECK-NEXT:    ret
+entry:
+  %not = xor i32 %m, -1
+  br label %for.body
+
+for.cond.cleanup:
+  ret void
+
+for.body:
+  %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ]
+  %arrayidx = getelementptr inbounds nuw i32, ptr %a, i64 %indvars.iv
+  %load = load i32, ptr %arrayidx, align 4
+  %and = and i32 %load, %not
+  store i32 %and, ptr %arrayidx, align 4
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  %exitcond.not = icmp eq i64 %indvars.iv.next, 16
+  br i1 %exitcond.not, label %for.cond.cleanup, label %for.body
+}
+
+define void @array_and_not_i64(ptr %a, i64 %m) {
+; CHECK-LABEL: array_and_not_i64:
+; CHECK:       // %bb.0: // %entry
+; CHECK-NEXT:    mov x8, xzr
+; CHECK-NEXT:    mvn x9, x1
+; CHECK-NEXT:  .LBB29_1: // %for.body
+; CHECK-NEXT:    // =>This Inner Loop Header: Depth=1
+; CHECK-NEXT:    ldr x10, [x0, x8]
+; CHECK-NEXT:    and x10, x10, x9
+; CHECK-NEXT:    str x10, [x0, x8]
+; CHECK-NEXT:    add x8, x8, #8
+; CHECK-NEXT:    cmp x8, #128
+; CHECK-NEXT:    b.ne .LBB29_1
+; CHECK-NEXT:  // %bb.2: // %for.cond.cleanup
+; CHECK-NEXT:    ret
+entry:
+  %not = xor i64 %m, -1
+  br label %for.body
+
+for.cond.cleanup:
+  ret void
+
+for.body:
+  %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ]
+  %arrayidx = getelementptr inbounds nuw i64, ptr %a, i64 %indvars.iv
+  %load = load i64, ptr %arrayidx, align 8
+  %and = and i64 %load, %not
+  store i64 %and, ptr %arrayidx, align 8
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  %exitcond.not = icmp eq i64 %indvars.iv.next, 16
+  br i1 %exitcond.not, label %for.cond.cleanup, label %for.body
+}
+
+define void @array_or_not_i8(ptr %a, i8 %m) {
+; CHECK-LABEL: array_or_not_i8:
+; CHECK:       // %bb.0: // %entry
+; CHECK-NEXT:    mov x8, xzr
+; CHECK-NEXT:    mvn w9, w1
+; CHECK-NEXT:  .LBB30_1: // %for.body
+; CHECK-NEXT:    // =>This Inner Loop Header: Depth=1
+; CHECK-NEXT:    ldrb w10, [x0, x8]
+; CHECK-NEXT:    orr w10, w10, w9
+; CHECK-NEXT:    strb w10, [x0, x8]
+; CHECK-NEXT:    add x8, x8, #1
+; CHECK-NEXT:    cmp x8, #16
+; CHECK-NEXT:    b.ne .LBB30_1
+; CHECK-NEXT:  // %bb.2: // %for.cond.cleanup
+; CHECK-NEXT:    ret
+entry:
+  %not = xor i8 %m, -1
+  br label %for.body
+
+for.cond.cleanup:
+  ret void
+
+for.body:
+  %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ]
+  %arrayidx = getelementptr inbounds nuw i8, ptr %a, i64 %indvars.iv
+  %load = load i8, ptr %arrayidx, align 1
+  %or = or i8 %load, %not
+  store i8 %or, ptr %arrayidx, align 1
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  %exitcond.not = icmp eq i64 %indvars.iv.next, 16
+  br i1 %exitcond.not, label %for.cond.cleanup, label %for.body
+}
+
+define void @array_or_not_i16(ptr %a, i16 %m) {
+; CHECK-LABEL: array_or_not_i16:
+; CHECK:       // %bb.0: // %entry
+; CHECK-NEXT:    mov x8, xzr
+; CHECK-NEXT:    mvn w9, w1
+; CHECK-NEXT:  .LBB31_1: // %for.body
+; CHECK-NEXT:    // =>This Inner Loop Header: Depth=1
+; CHECK-NEXT:    ldrh w10, [x0, x8]
+; CHECK-NEXT:    orr w10, w10, w9
+; CHECK-NEXT:    strh w10, [x0, x8]
+; CHECK-NEXT:    add x8, x8, #2
+; CHECK-NEXT:    cmp x8, #32
+; CHECK-NEXT:    b.ne .LBB31_1
+; CHECK-NEXT:  // %bb.2: // %for.cond.cleanup
+; CHECK-NEXT:    ret
+entry:
+  %not = xor i16 %m, -1
+  br label %for.body
+
+for.cond.cleanup:
+  ret void
+
+for.body:
+  %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ]
+  %arrayidx = getelementptr inbounds nuw i16, ptr %a, i64 %indvars.iv
+  %load = load i16, ptr %arrayidx, align 2
+  %or = or i16 %load, %not
+  store i16 %or, ptr %arrayidx, align 2
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  %exitcond.not = icmp eq i64 %indvars.iv.next, 16
+  br i1 %exitcond.not, label %for.cond.cleanup, label %for.body
+}
+
+define void @array_or_not_i32(ptr %a, i32 %m) {
+; CHECK-LABEL: array_or_not_i32:
+; CHECK:       // %bb.0: // %entry
+; CHECK-NEXT:    mov x8, xzr
+; CHECK-NEXT:    mvn w9, w1
+; CHECK-NEXT:  .LBB32_1: // %for.body
+; CHECK-NEXT:    // =>This Inner Loop Header: Depth=1
+; CHECK-NEXT:    ldr w10, [x0, x8]
+; CHECK-NEXT:    orr w10, w10, w9
+; CHECK-NEXT:    str w10, [x0, x8]
+; CHECK-NEXT:    add x8, x8, #4
+; CHECK-NEXT:    cmp x8, #64
+; CHECK-NEXT:    b.ne .LBB32_1
+; CHECK-NEXT:  // %bb.2: // %for.cond.cleanup
+; CHECK-NEXT:    ret
+entry:
+  %not = xor i32 %m, -1
+  br label %for.body
+
+for.cond.cleanup:
+  ret void
+
+for.body:
+  %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ]
+  %arrayidx = getelementptr inbounds nuw i32, ptr %a, i64 %indvars.iv
+  %load = load i32, ptr %arrayidx, align 4
+  %or = or i32 %load, %not
+  store i32 %or, ptr %arrayidx, align 4
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  %exitcond.not = icmp eq i64 %indvars.iv.next, 16
+  br i1 %exitcond.not, label %for.cond.cleanup, label %for.body
+}
+
+define void @array_or_not_i64(ptr %a, i64 %m) {
+; CHECK-LABEL: array_or_not_i64:
+; CHECK:       // %bb.0: // %entry
+; CHECK-NEXT:    mov x8, xzr
+; CHECK-NEXT:    mvn x9, x1
+; CHECK-NEXT:  .LBB33_1: // %for.body
+; CHECK-NEXT:    // =>This Inner Loop Header: Depth=1
+; CHECK-NEXT:    ldr x10, [x0, x8]
+; CHECK-NEXT:    orr x10, x10, x9
+; CHECK-NEXT:    str x10, [x0, x8]
+; CHECK-NEXT:    add x8, x8, #8
+; CHECK-NEXT:    cmp x8, #128
+; CHECK-NEXT:    b.ne .LBB33_1
+; CHECK-NEXT:  // %bb.2: // %for.cond.cleanup
+; CHECK-NEXT:    ret
+entry:
+  %not = xor i64 %m, -1
+  br label %for.body
+
+for.cond.cleanup:
+  ret void
+
+for.body:
+  %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ]
+  %arrayidx = getelementptr inbounds nuw i64, ptr %a, i64 %indvars.iv
+  %load = load i64, ptr %arrayidx, align 8
+  %or = or i64 %load, %not
+  store i64 %or, ptr %arrayidx, align 8
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  %exitcond.not = icmp eq i64 %indvars.iv.next, 16
+  br i1 %exitcond.not, label %for.cond.cleanup, label %for.body
+}
+
+define void @array_xor_not_i8(ptr %a, i8 %m) {
+; CHECK-LABEL: array_xor_not_i8:
+; CHECK:       // %bb.0: // %entry
+; CHECK-NEXT:    mov x8, xzr
+; CHECK-NEXT:    mvn w9, w1
+; CHECK-NEXT:  .LBB34_1: // %for.body
+; CHECK-NEXT:    // =>This Inner Loop Header: Depth=1
+; CHECK-NEXT:    ldrb w10, [x0, x8]
+; CHECK-NEXT:    eor w10, w10, w9
+; CHECK-NEXT:    strb w10, [x0, x8]
+; CHECK-NEXT:    add x8, x8, #1
+; CHECK-NEXT:    cmp x8, #16
+; CHECK-NEXT:    b.ne .LBB34_1
+; CHECK-NEXT:  // %bb.2: // %for.cond.cleanup
+; CHECK-NEXT:    ret
+entry:
+  %not = xor i8 %m, -1
+  br label %for.body
+
+for.cond.cleanup:
+  ret void
+
+for.body:
+  %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ]
+  %arrayidx = getelementptr inbounds nuw i8, ptr %a, i64 %indvars.iv
+  %load = load i8, ptr %arrayidx, align 1
+  %xor = xor i8 %load, %not
+  store i8 %xor, ptr %arrayidx, align 1
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  %exitcond.not = icmp eq i64 %indvars.iv.next, 16
+  br i1 %exitcond.not, label %for.cond.cleanup, label %for.body
+}
+
+define void @array_xor_not_i16(ptr %a, i16 %m) {
+; CHECK-LABEL: array_xor_not_i16:
+; CHECK:       // %bb.0: // %entry
+; CHECK-NEXT:    mov x8, xzr
+; CHECK-NEXT:    mvn w9, w1
+; CHECK-NEXT:  .LBB35_1: // %for.body
+; CHECK-NEXT:    // =>This Inner Loop Header: Depth=1
+; CHECK-NEXT:    ldrh w10, [x0, x8]
+; CHECK-NEXT:    eor w10, w10, w9
+; CHECK-NEXT:    strh w10, [x0, x8]
+; CHECK-NEXT:    add x8, x8, #2
+; CHECK-NEXT:    cmp x8, #32
+; CHECK-NEXT:    b.ne .LBB35_1
+; CHECK-NEXT:  // %bb.2: // %for.cond.cleanup
+; CHECK-NEXT:    ret
+entry:
+  %not = xor i16 %m, -1
+  br label %for.body
+
+for.cond.cleanup:
+  ret void
+
+for.body:
+  %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ]
+  %arrayidx = getelementptr inbounds nuw i16, ptr %a, i64 %indvars.iv
+  %load = load i16, ptr %arrayidx, align 2
+  %xor = xor i16 %load, %not
+  store i16 %xor, ptr %arrayidx, align 2
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  %exitcond.not = icmp eq i64 %indvars.iv.next, 16
+  br i1 %exitcond.not, label %for.cond.cleanup, label %for.body
+}
+
+define void @array_xor_not_i32(ptr %a, i32 %m) {
+; CHECK-LABEL: array_xor_not_i32:
+; CHECK:       // %bb.0: // %entry
+; CHECK-NEXT:    mov x8, xzr
+; CHECK-NEXT:    mvn w9, w1
+; CHECK-NEXT:  .LBB36_1: // %for.body
+; CHECK-NEXT:    // =>This Inner Loop Header: Depth=1
+; CHECK-NEXT:    ldr w10, [x0, x8]
+; CHECK-NEXT:    eor w10, w10, w9
+; CHECK-NEXT:    str w10, [x0, x8]
+; CHECK-NEXT:    add x8, x8, #4
+; CHECK-NEXT:    cmp x8, #64
+; CHECK-NEXT:    b.ne .LBB36_1
+; CHECK-NEXT:  // %bb.2: // %for.cond.cleanup
+; CHECK-NEXT:    ret
+entry:
+  %not = xor i32 %m, -1
+  br label %for.body
+
+for.cond.cleanup:
+  ret void
+
+for.body:
+  %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ]
+  %arrayidx = getelementptr inbounds nuw i32, ptr %a, i64 %indvars.iv
+  %load = load i32, ptr %arrayidx, align 4
+  %xor = xor i32 %load, %not
+  store i32 %xor, ptr %arrayidx, align 4
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  %exitcond.not = icmp eq i64 %indvars.iv.next, 16
+  br i1 %exitcond.not, label %for.cond.cleanup, label %for.body
+}
+
+define void @array_xor_not_i64(ptr %a, i64 %m) {
+; CHECK-LABEL: array_xor_not_i64:
+; CHECK:       // %bb.0: // %entry
+; CHECK-NEXT:    mov x8, xzr
+; CHECK-NEXT:    mvn x9, x1
+; CHECK-NEXT:  .LBB37_1: // %for.body
+; CHECK-NEXT:    // =>This Inner Loop Header: Depth=1
+; CHECK-NEXT:    ldr x10, [x0, x8]
+; CHECK-NEXT:    eor x10, x10, x9
+; CHECK-NEXT:    str x10, [x0, x8]
+; CHECK-NEXT:    add x8, x8, #8
+; CHECK-NEXT:    cmp x8, #128
+; CHECK-NEXT:    b.ne .LBB37_1
+; CHECK-NEXT:  // %bb.2: // %for.cond.cleanup
+; CHECK-NEXT:    ret
+entry:
+  %not = xor i64 %m, -1
+  br label %for.body
+
+for.cond.cleanup:
+  ret void
+
+for.body:
+  %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ]
+  %arrayidx = getelementptr inbounds nuw i64, ptr %a, i64 %indvars.iv
+  %load = load i64, ptr %arrayidx, align 8
+  %xor = xor i64 %load, %not
+  store i64 %xor, ptr %arrayidx, align 8
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  %exitcond.not = icmp eq i64 %indvars.iv.next, 16
+  br i1 %exitcond.not, label %for.cond.cleanup, label %for.body
+}
diff --git a/llvm/test/CodeGen/AArch64/neon-bitwise-instructions.ll b/llvm/test/CodeGen/AArch64/neon-bitwise-instructions.ll
index ac7c6c00e0533..9c936161e5b34 100644
--- a/llvm/test/CodeGen/AArch64/neon-bitwise-instructions.ll
+++ b/llvm/test/CodeGen/AArch64/neon-bitwise-instructions.ll
@@ -3388,3 +3388,667 @@ define <2 x i64> @or_dup_not_v2i64(<2 x i64> %a, i64 %m) {
   %or = or <2 x i64> %a, %shuffle
   ret <2 x i64> %or
 }
+
+define void @array_and_not_v16i8(ptr %a, <16 x i8> %m) {
+; CHECK-SD-LABEL: array_and_not_v16i8:
+; CHECK-SD:       // %bb.0: // %entry
+; CHECK-SD-NEXT:    mvn v0.16b, v0.16b
+; CHECK-SD-NEXT:    mov x8, xzr
+; CHECK-SD-NEXT:  .LBB211_1: // %vector.body
+; CHECK-SD-NEXT:    // =>This Inner Loop Header: Depth=1
+; CHECK-SD-NEXT:    ldr q1, [x0, x8]
+; CHECK-SD-NEXT:    and v1.16b, v1.16b, v0.16b
+; CHECK-SD-NEXT:    str q1, [x0, x8]
+; CHECK-SD-NEXT:    add x8, x8, #16
+; CHECK-SD-NEXT:    cmp x8, #256
+; CHECK-SD-NEXT:    b.ne .LBB211_1
+; CHECK-SD-NEXT:  // %bb.2: // %for.cond.cleanup
+; CHECK-SD-NEXT:    ret
+;
+; CHECK-GI-LABEL: array_and_not_v16i8:
+; CHECK-GI:       // %bb.0: // %entry
+; CHECK-GI-NEXT:    mov x8, xzr
+; CHECK-GI-NEXT:  .LBB211_1: // %vector.body
+; CHECK-GI-NEXT:    // =>This Inner Loop Header: Depth=1
+; CHECK-GI-NEXT:    ldr q1, [x0, x8]
+; CHECK-GI-NEXT:    bic v1.16b, v1.16b, v0.16b
+; CHECK-GI-NEXT:    str q1, [x0, x8]
+; CHECK-GI-NEXT:    add x8, x8, #16
+; CHECK-GI-NEXT:    cmp x8, #256
+; CHECK-GI-NEXT:    b.ne .LBB211_1
+; CHECK-GI-NEXT:  // %bb.2: // %for.cond.cleanup
+; CHECK-GI-NEXT:    ret
+entry:
+  %not = xor <16 x i8> %m, splat (i8 -1)
+  br label %vector.body
+
+vector.body:
+  %index = phi i64 [ 0, %entry ], [ %index.next, %vector.body ]
+  %gep = getelementptr inbounds nuw i8, ptr %a, i64 %index
+  %wide.load = load <16 x i8>, ptr %gep, align 1
+  %1 = and <16 x i8> %wide.load, %not
+  store <16 x i8> %1, ptr %gep, align 1
+  %index.next = add nuw i64 %index, 16
+  %2 = icmp eq i64 %index.next, 256
+  br i1 %2, label %for.cond.cleanup, label %vector.body
+
+for.cond.cleanup:
+  ret void
+}
+
+define void @array_and_not_v8i16(ptr %a, <8 x i16> %m) {
+; CHECK-SD-LABEL: array_and_not_v8i16:
+; CHECK-SD:       // %bb.0: // %entry
+; CHECK-SD-NEXT:    mvn v0.16b, v0.16b
+; CHECK-SD-NEXT:    mov x8, xzr
+; CHECK-SD-NEXT:  .LBB212_1: // %vector.body
+; CHECK-SD-NEXT:    // =>This Inner Loop Header: Depth=1
+; CHECK-SD-NEXT:    ldr q1, [x0, x8]
+; CHECK-SD-NEXT:    and v1.16b, v1.16b, v0.16b
+; CHECK-SD-NEXT:    str q1, [x0, x8]
+; CHECK-SD-NEXT:    add x8, x8, #16
+; CHECK-SD-NEXT:    cmp x8, #512
+; CHECK-SD-NEXT:    b.ne .LBB212_1
+; CHECK-SD-NEXT:  // %bb.2: // %for.cond.cleanup
+; CHECK-SD-NEXT:    ret
+;
+; CHECK-GI-LABEL: array_and_not_v8i16:
+; CHECK-GI:       // %bb.0: // %entry
+; CHECK-GI-NEXT:    mov x8, xzr
+; CHECK-GI-NEXT:  .LBB212_1: // %vector.body
+; CHECK-GI-NEXT:    // =>This Inner Loop Header: Depth=1
+; CHECK-GI-NEXT:    ldr q1, [x0, x8]
+; CHECK-GI-NEXT:    bic v1.16b, v1.16b, v0.16b
+; CHECK-GI-NEXT:    str q1, [x0, x8]
+; CHECK-GI-NEXT:    add x8, x8, #16
+; CHECK-GI-NEXT:    cmp x8, #512
+; CHECK-GI-NEXT:    b.ne .LBB212_1
+; CHECK-GI-NEXT:  // %bb.2: // %for.cond.cleanup
+; CHECK-GI-NEXT:    ret
+entry:
+  %not = xor <8 x i16> %m, splat (i16 -1)
+  br label %vector.body
+
+vector.body:
+  %index = phi i64 [ 0, %entry ], [ %index.next, %vector.body ]
+  %gep = getelementptr inbounds nuw i16, ptr %a, i64 %index
+  %wide.load = load <8 x i16>, ptr %gep, align 2
+  %1 = and <8 x i16> %wide.load, %not
+  store <8 x i16> %1, ptr %gep, align 2
+  %index.next = add nuw i64 %index, 8
+  %2 = icmp eq i64 %index.next, 256
+  br i1 %2, label %for.cond.cleanup, label %vector.body
+
+for.cond.cleanup:
+  ret void
+}
+
+define void @array_and_not_v4i32(ptr %a, <4 x i32> %m) {
+; CHECK-SD-LABEL: array_and_not_v4i32:
+; CHECK-SD:       // %bb.0: // %entry
+; CHECK-SD-NEXT:    mvn v0.16b, v0.16b
+; CHECK-SD-NEXT:    mov x8, xzr
+; CHECK-SD-NEXT:  .LBB213_1: // %vector.body
+; CHECK-SD-NEXT:    // =>This Inner Loop Header: Depth=1
+; CHECK-SD-NEXT:    ldr q1, [x0, x8]
+; CHECK-SD-NEXT:    and v1.16b, v1.16b, v0.16b
+; CHECK-SD-NEXT:    str q1, [x0, x8]
+; CHECK-SD-NEXT:    add x8, x8, #16
+; CHECK-SD-NEXT:    cmp x8, #1024
+; CHECK-SD-NEXT:    b.ne .LBB213_1
+; CHECK-SD-NEXT:  // %bb.2: // %for.cond.cleanup
+; CHECK-SD-NEXT:    ret
+;
+; CHECK-GI-LABEL: array_and_not_v4i32:
+; CHECK-GI:       // %bb.0: // %entry
+; CHECK-GI-NEXT:    mov x8, xzr
+; CHECK-GI-NEXT:  .LBB213_1: // %vector.body
+; CHECK-GI-NEXT:    // =>This Inner Loop Header: Depth=1
+; CHECK-GI-NEXT:    ldr q1, [x0, x8]
+; CHECK-GI-NEXT:    bic v1.16b, v1.16b, v0.16b
+; CHECK-GI-NEXT:    str q1, [x0, x8]
+; CHECK-GI-NEXT:    add x8, x8, #16
+; CHECK-GI-NEXT:    cmp x8, #1024
+; CHECK-GI-NEXT:    b.ne .LBB213_1
+; CHECK-GI-NEXT:  // %bb.2: // %for.cond.cleanup
+; CHECK-GI-NEXT:    ret
+entry:
+  %not = xor <4 x i32> %m, splat (i32 -1)
+  br label %vector.body
+
+vector.body:
+  %index = phi i64 [ 0, %entry ], [ %index.next, %vector.body ]
+  %gep = getelementptr inbounds nuw i32, ptr %a, i64 %index
+  %wide.load = load <4 x i32>, ptr %gep, align 4
+  %1 = and <4 x i32> %wide.load, %not
+  store <4 x i32> %1, ptr %gep, align 4
+  %index.next = add nuw i64 %index, 4
+  %2 = icmp eq i64 %index.next, 256
+  br i1 %2, label %for.cond.cleanup, label %vector.body
+
+for.cond.cleanup:
+  ret void
+}
+
+define void @array_and_not_v2i64(ptr %a, <2 x i64> %m) {
+; CHECK-SD-LABEL: array_and_not_v2i64:
+; CHECK-SD:       // %bb.0: // %entry
+; CHECK-SD-NEXT:    mvn v0.16b, v0.16b
+; CHECK-SD-NEXT:    mov x8, xzr
+; CHECK-SD-NEXT:  .LBB214_1: // %vector.body
+; CHECK-SD-NEXT:    // =>This Inner Loop Header: Depth=1
+; CHECK-SD-NEXT:    ldr q1, [x0, x8]
+; CHECK-SD-NEXT:    and v1.16b, v1.16b, v0.16b
+; CHECK-SD-NEXT:    str q1, [x0, x8]
+; CHECK-SD-NEXT:    add x8, x8, #16
+; CHECK-SD-NEXT:    cmp x8, #2048
+; CHECK-SD-NEXT:    b.ne .LBB214_1
+; CHECK-SD-NEXT:  // %bb.2: // %for.cond.cleanup
+; CHECK-SD-NEXT:    ret
+;
+; CHECK-GI-LABEL: array_and_not_v2i64:
+; CHECK-GI:       // %bb.0: // %entry
+; CHECK-GI-NEXT:    mov x8, xzr
+; CHECK-GI-NEXT:  .LBB214_1: // %vector.body
+; CHECK-GI-NEXT:    // =>This Inner Loop Header: Depth=1
+; CHECK-GI-NEXT:    ldr q1, [x0, x8]
+; CHECK-GI-NEXT:    bic v1.16b, v1.16b, v0.16b
+; CHECK-GI-NEXT:    str q1, [x0, x8]
+; CHECK-GI-NEXT:    add x8, x8, #16
+; CHECK-GI-NEXT:    cmp x8, #2048
+; CHECK-GI-NEXT:    b.ne .LBB214_1
+; CHECK-GI-NEXT:  // %bb.2: // %for.cond.cleanup
+; CHECK-GI-NEXT:    ret
+entry:
+  %not = xor <2 x i64> %m, splat (i64 -1)
+  br label %vector.body
+
+vector.body:
+  %index = phi i64 [ 0, %entry ], [ %index.next, %vector.body ]
+  %gep = getelementptr inbounds nuw i64, ptr %a, i64 %index
+  %wide.load = load <2 x i64>, ptr %gep, align 8
+  %1 = and <2 x i64> %wide.load, %not
+  store <2 x i64> %1, ptr %gep, align 8
+  %index.next = add nuw i64 %index, 2
+  %2 = icmp eq i64 %index.next, 256
+  br i1 %2, label %for.cond.cleanup, label %vector.body
+
+for.cond.cleanup:
+  ret void
+}
+
+define void @array_or_not_v16i8(ptr %a, <16 x i8> %m) {
+; CHECK-SD-LABEL: array_or_not_v16i8:
+; CHECK-SD:       // %bb.0: // %entry
+; CHECK-SD-NEXT:    mvn v0.16b, v0.16b
+; CHECK-SD-NEXT:    mov x8, xzr
+; CHECK-SD-NEXT:  .LBB215_1: // %vector.body
+; CHECK-SD-NEXT:    // =>This Inner Loop Header: Depth=1
+; CHECK-SD-NEXT:    ldr q1, [x0, x8]
+; CHECK-SD-NEXT:    orr v1.16b, v1.16b, v0.16b
+; CHECK-SD-NEXT:    str q1, [x0, x8]
+; CHECK-SD-NEXT:    add x8, x8, #16
+; CHECK-SD-NEXT:    cmp x8, #256
+; CHECK-SD-NEXT:    b.ne .LBB215_1
+; CHECK-SD-NEXT:  // %bb.2: // %for.cond.cleanup
+; CHECK-SD-NEXT:    ret
+;
+; CHECK-GI-LABEL: array_or_not_v16i8:
+; CHECK-GI:       // %bb.0: // %entry
+; CHECK-GI-NEXT:    mov x8, xzr
+; CHECK-GI-NEXT:  .LBB215_1: // %vector.body
+; CHECK-GI-NEXT:    // =>This Inner Loop Header: Depth=1
+; CHECK-GI-NEXT:    ldr q1, [x0, x8]
+; CHECK-GI-NEXT:    orn v1.16b, v1.16b, v0.16b
+; CHECK-GI-NEXT:    str q1, [x0, x8]
+; CHECK-GI-NEXT:    add x8, x8, #16
+; CHECK-GI-NEXT:    cmp x8, #256
+; CHECK-GI-NEXT:    b.ne .LBB215_1
+; CHECK-GI-NEXT:  // %bb.2: // %for.cond.cleanup
+; CHECK-GI-NEXT:    ret
+entry:
+  %not = xor <16 x i8> %m, splat (i8 -1)
+  br label %vector.body
+
+vector.body:
+  %index = phi i64 [ 0, %entry ], [ %index.next, %vector.body ]
+  %gep = getelementptr inbounds nuw i8, ptr %a, i64 %index
+  %wide.load = load <16 x i8>, ptr %gep, align 1
+  %1 = or <16 x i8> %wide.load, %not
+  store <16 x i8> %1, ptr %gep, align 1
+  %index.next = add nuw i64 %index, 16
+  %2 = icmp eq i64 %index.next, 256
+  br i1 %2, label %for.cond.cleanup, label %vector.body
+
+for.cond.cleanup:
+  ret void
+}
+
+define void @array_or_not_v8i16(ptr %a, <8 x i16> %m) {
+; CHECK-SD-LABEL: array_or_not_v8i16:
+; CHECK-SD:       // %bb.0: // %entry
+; CHECK-SD-NEXT:    mvn v0.16b, v0.16b
+; CHECK-SD-NEXT:    mov x8, xzr
+; CHECK-SD-NEXT:  .LBB216_1: // %vector.body
+; CHECK-SD-NEXT:    // =>This Inner Loop Header: Depth=1
+; CHECK-SD-NEXT:    ldr q1, [x0, x8]
+; CHECK-SD-NEXT:    orr v1.16b, v1.16b, v0.16b
+; CHECK-SD-NEXT:    str q1, [x0, x8]
+; CHECK-SD-NEXT:    add x8, x8, #16
+; CHECK-SD-NEXT:    cmp x8, #512
+; CHECK-SD-NEXT:    b.ne .LBB216_1
+; CHECK-SD-NEXT:  // %bb.2: // %for.cond.cleanup
+; CHECK-SD-NEXT:    ret
+;
+; CHECK-GI-LABEL: array_or_not_v8i16:
+; CHECK-GI:       // %bb.0: // %entry
+; CHECK-GI-NEXT:    mov x8, xzr
+; CHECK-GI-NEXT:  .LBB216_1: // %vector.body
+; CHECK-GI-NEXT:    // =>This Inner Loop Header: Depth=1
+; CHECK-GI-NEXT:    ldr q1, [x0, x8]
+; CHECK-GI-NEXT:    orn v1.16b, v1.16b, v0.16b
+; CHECK-GI-NEXT:    str q1, [x0, x8]
+; CHECK-GI-NEXT:    add x8, x8, #16
+; CHECK-GI-NEXT:    cmp x8, #512
+; CHECK-GI-NEXT:    b.ne .LBB216_1
+; CHECK-GI-NEXT:  // %bb.2: // %for.cond.cleanup
+; CHECK-GI-NEXT:    ret
+entry:
+  %not = xor <8 x i16> %m, splat (i16 -1)
+  br label %vector.body
+
+vector.body:
+  %index = phi i64 [ 0, %entry ], [ %index.next, %vector.body ]
+  %gep = getelementptr inbounds nuw i16, ptr %a, i64 %index
+  %wide.load = load <8 x i16>, ptr %gep, align 2
+  %1 = or <8 x i16> %wide.load, %not
+  store <8 x i16> %1, ptr %gep, align 2
+  %index.next = add nuw i64 %index, 8
+  %2 = icmp eq i64 %index.next, 256
+  br i1 %2, label %for.cond.cleanup, label %vector.body
+
+for.cond.cleanup:
+  ret void
+}
+
+define void @array_or_not_v4i32(ptr %a, <4 x i32> %m) {
+; CHECK-SD-LABEL: array_or_not_v4i32:
+; CHECK-SD:       // %bb.0: // %entry
+; CHECK-SD-NEXT:    mvn v0.16b, v0.16b
+; CHECK-SD-NEXT:    mov x8, xzr
+; CHECK-SD-NEXT:  .LBB217_1: // %vector.body
+; CHECK-SD-NEXT:    // =>This Inner Loop Header: Depth=1
+; CHECK-SD-NEXT:    ldr q1, [x0, x8]
+; CHECK-SD-NEXT:    orr v1.16b, v1.16b, v0.16b
+; CHECK-SD-NEXT:    str q1, [x0, x8]
+; CHECK-SD-NEXT:    add x8, x8, #16
+; CHECK-SD-NEXT:    cmp x8, #1024
+; CHECK-SD-NEXT:    b.ne .LBB217_1
+; CHECK-SD-NEXT:  // %bb.2: // %for.cond.cleanup
+; CHECK-SD-NEXT:    ret
+;
+; CHECK-GI-LABEL: array_or_not_v4i32:
+; CHECK-GI:       // %bb.0: // %entry
+; CHECK-GI-NEXT:    mov x8, xzr
+; CHECK-GI-NEXT:  .LBB217_1: // %vector.body
+; CHECK-GI-NEXT:    // =>This Inner Loop Header: Depth=1
+; CHECK-GI-NEXT:    ldr q1, [x0, x8]
+; CHECK-GI-NEXT:    orn v1.16b, v1.16b, v0.16b
+; CHECK-GI-NEXT:    str q1, [x0, x8]
+; CHECK-GI-NEXT:    add x8, x8, #16
+; CHECK-GI-NEXT:    cmp x8, #1024
+; CHECK-GI-NEXT:    b.ne .LBB217_1
+; CHECK-GI-NEXT:  // %bb.2: // %for.cond.cleanup
+; CHECK-GI-NEXT:    ret
+entry:
+  %not = xor <4 x i32> %m, splat (i32 -1)
+  br label %vector.body
+
+vector.body:
+  %index = phi i64 [ 0, %entry ], [ %index.next, %vector.body ]
+  %gep = getelementptr inbounds nuw i32, ptr %a, i64 %index
+  %wide.load = load <4 x i32>, ptr %gep, align 4
+  %1 = or <4 x i32> %wide.load, %not
+  store <4 x i32> %1, ptr %gep, align 4
+  %index.next = add nuw i64 %index, 4
+  %2 = icmp eq i64 %index.next, 256
+  br i1 %2, label %for.cond.cleanup, label %vector.body
+
+for.cond.cleanup:
+  ret void
+}
+
+define void @array_or_not_v2i64(ptr %a, <2 x i64> %m) {
+; CHECK-SD-LABEL: array_or_not_v2i64:
+; CHECK-SD:       // %bb.0: // %entry
+; CHECK-SD-NEXT:    mvn v0.16b, v0.16b
+; CHECK-SD-NEXT:    mov x8, xzr
+; CHECK-SD-NEXT:  .LBB218_1: // %vector.body
+; CHECK-SD-NEXT:    // =>This Inner Loop Header: Depth=1
+; CHECK-SD-NEXT:    ldr q1, [x0, x8]
+; CHECK-SD-NEXT:    orr v1.16b, v1.16b, v0.16b
+; CHECK-SD-NEXT:    str q1, [x0, x8]
+; CHECK-SD-NEXT:    add x8, x8, #16
+; CHECK-SD-NEXT:    cmp x8, #2048
+; CHECK-SD-NEXT:    b.ne .LBB218_1
+; CHECK-SD-NEXT:  // %bb.2: // %for.cond.cleanup
+; CHECK-SD-NEXT:    ret
+;
+; CHECK-GI-LABEL: array_or_not_v2i64:
+; CHECK-GI:       // %bb.0: // %entry
+; CHECK-GI-NEXT:    mov x8, xzr
+; CHECK-GI-NEXT:  .LBB218_1: // %vector.body
+; CHECK-GI-NEXT:    // =>This Inner Loop Header: Depth=1
+; CHECK-GI-NEXT:    ldr q1, [x0, x8]
+; CHECK-GI-NEXT:    orn v1.16b, v1.16b, v0.16b
+; CHECK-GI-NEXT:    str q1, [x0, x8]
+; CHECK-GI-NEXT:    add x8, x8, #16
+; CHECK-GI-NEXT:    cmp x8, #2048
+; CHECK-GI-NEXT:    b.ne .LBB218_1
+; CHECK-GI-NEXT:  // %bb.2: // %for.cond.cleanup
+; CHECK-GI-NEXT:    ret
+entry:
+  %not = xor <2 x i64> %m, splat (i64 -1)
+  br label %vector.body
+
+vector.body:
+  %index = phi i64 [ 0, %entry ], [ %index.next, %vector.body ]
+  %gep = getelementptr inbounds nuw i64, ptr %a, i64 %index
+  %wide.load = load <2 x i64>, ptr %gep, align 8
+  %1 = or <2 x i64> %wide.load, %not
+  store <2 x i64> %1, ptr %gep, align 8
+  %index.next = add nuw i64 %index, 2
+  %2 = icmp eq i64 %index.next, 256
+  br i1 %2, label %for.cond.cleanup, label %vector.body
+
+for.cond.cleanup:
+  ret void
+}
+
+define void @array_and_not_dup_v16i8(ptr %a, i8 %m) {
+; CHECK-LABEL: array_and_not_dup_v16i8:
+; CHECK:       // %bb.0: // %entry
+; CHECK-NEXT:    mvn w8, w1
+; CHECK-NEXT:    dup v0.16b, w8
+; CHECK-NEXT:    mov x8, xzr
+; CHECK-NEXT:  .LBB219_1: // %vector.body
+; CHECK-NEXT:    // =>This Inner Loop Header: Depth=1
+; CHECK-NEXT:    ldr q1, [x0, x8]
+; CHECK-NEXT:    and v1.16b, v1.16b, v0.16b
+; CHECK-NEXT:    str q1, [x0, x8]
+; CHECK-NEXT:    add x8, x8, #16
+; CHECK-NEXT:    cmp x8, #256
+; CHECK-NEXT:    b.ne .LBB219_1
+; CHECK-NEXT:  // %bb.2: // %for.cond.cleanup
+; CHECK-NEXT:    ret
+entry:
+  %not = xor i8 %m, -1
+  %broadcast.splatinsert = insertelement <16 x i8> poison, i8 %not, i64 0
+  %broadcast.splat = shufflevector <16 x i8> %broadcast.splatinsert, <16 x i8> poison, <16 x i32> zeroinitializer
+  br label %vector.body
+
+vector.body:
+  %index = phi i64 [ 0, %entry ], [ %index.next, %vector.body ]
+  %gep = getelementptr inbounds nuw i8, ptr %a, i64 %index
+  %wide.load = load <16 x i8>, ptr %gep, align 1
+  %1 = and <16 x i8> %wide.load, %broadcast.splat
+  store <16 x i8> %1, ptr %gep, align 1
+  %index.next = add nuw i64 %index, 16
+  %2 = icmp eq i64 %index.next, 256
+  br i1 %2, label %for.cond.cleanup, label %vector.body
+
+for.cond.cleanup:
+  ret void
+}
+
+define void @array_and_not_dup_v8i16(ptr %a, i16 %m) {
+; CHECK-LABEL: array_and_not_dup_v8i16:
+; CHECK:       // %bb.0: // %entry
+; CHECK-NEXT:    mvn w8, w1
+; CHECK-NEXT:    dup v0.8h, w8
+; CHECK-NEXT:    mov x8, xzr
+; CHECK-NEXT:  .LBB220_1: // %vector.body
+; CHECK-NEXT:    // =>This Inner Loop Header: Depth=1
+; CHECK-NEXT:    ldr q1, [x0, x8]
+; CHECK-NEXT:    and v1.16b, v1.16b, v0.16b
+; CHECK-NEXT:    str q1, [x0, x8]
+; CHECK-NEXT:    add x8, x8, #16
+; CHECK-NEXT:    cmp x8, #512
+; CHECK-NEXT:    b.ne .LBB220_1
+; CHECK-NEXT:  // %bb.2: // %for.cond.cleanup
+; CHECK-NEXT:    ret
+entry:
+  %not = xor i16 %m, -1
+  %broadcast.splatinsert = insertelement <8 x i16> poison, i16 %not, i64 0
+  %broadcast.splat = shufflevector <8 x i16> %broadcast.splatinsert, <8 x i16> poison, <8 x i32> zeroinitializer
+  br label %vector.body
+
+vector.body:
+  %index = phi i64 [ 0, %entry ], [ %index.next, %vector.body ]
+  %gep = getelementptr inbounds nuw i16, ptr %a, i64 %index
+  %wide.load = load <8 x i16>, ptr %gep, align 2
+  %1 = and <8 x i16> %wide.load, %broadcast.splat
+  store <8 x i16> %1, ptr %gep, align 2
+  %index.next = add nuw i64 %index, 8
+  %2 = icmp eq i64 %index.next, 256
+  br i1 %2, label %for.cond.cleanup, label %vector.body
+
+for.cond.cleanup:
+  ret void
+}
+
+define void @array_and_not_dup_v4i32(ptr %a, i32 %m) {
+; CHECK-LABEL: array_and_not_dup_v4i32:
+; CHECK:       // %bb.0: // %entry
+; CHECK-NEXT:    mvn w8, w1
+; CHECK-NEXT:    dup v0.4s, w8
+; CHECK-NEXT:    mov x8, xzr
+; CHECK-NEXT:  .LBB221_1: // %vector.body
+; CHECK-NEXT:    // =>This Inner Loop Header: Depth=1
+; CHECK-NEXT:    ldr q1, [x0, x8]
+; CHECK-NEXT:    and v1.16b, v1.16b, v0.16b
+; CHECK-NEXT:    str q1, [x0, x8]
+; CHECK-NEXT:    add x8, x8, #16
+; CHECK-NEXT:    cmp x8, #1024
+; CHECK-NEXT:    b.ne .LBB221_1
+; CHECK-NEXT:  // %bb.2: // %for.cond.cleanup
+; CHECK-NEXT:    ret
+entry:
+  %not = xor i32 %m, -1
+  %broadcast.splatinsert = insertelement <4 x i32> poison, i32 %not, i64 0
+  %broadcast.splat = shufflevector <4 x i32> %broadcast.splatinsert, <4 x i32> poison, <4 x i32> zeroinitializer
+  br label %vector.body
+
+vector.body:
+  %index = phi i64 [ 0, %entry ], [ %index.next, %vector.body ]
+  %gep = getelementptr inbounds nuw i32, ptr %a, i64 %index
+  %wide.load = load <4 x i32>, ptr %gep, align 4
+  %1 = and <4 x i32> %wide.load, %broadcast.splat
+  store <4 x i32> %1, ptr %gep, align 4
+  %index.next = add nuw i64 %index, 4
+  %2 = icmp eq i64 %index.next, 256
+  br i1 %2, label %for.cond.cleanup, label %vector.body
+
+for.cond.cleanup:
+  ret void
+}
+
+define void @array_and_not_dup_v2i64(ptr %a, i64 %m) {
+; CHECK-LABEL: array_and_not_dup_v2i64:
+; CHECK:       // %bb.0: // %entry
+; CHECK-NEXT:    mvn x8, x1
+; CHECK-NEXT:    dup v0.2d, x8
+; CHECK-NEXT:    mov x8, xzr
+; CHECK-NEXT:  .LBB222_1: // %vector.body
+; CHECK-NEXT:    // =>This Inner Loop Header: Depth=1
+; CHECK-NEXT:    ldr q1, [x0, x8]
+; CHECK-NEXT:    and v1.16b, v1.16b, v0.16b
+; CHECK-NEXT:    str q1, [x0, x8]
+; CHECK-NEXT:    add x8, x8, #16
+; CHECK-NEXT:    cmp x8, #2048
+; CHECK-NEXT:    b.ne .LBB222_1
+; CHECK-NEXT:  // %bb.2: // %for.cond.cleanup
+; CHECK-NEXT:    ret
+entry:
+  %not = xor i64 %m, -1
+  %broadcast.splatinsert = insertelement <2 x i64> poison, i64 %not, i64 0
+  %broadcast.splat = shufflevector <2 x i64> %broadcast.splatinsert, <2 x i64> poison, <2 x i32> zeroinitializer
+  br label %vector.body
+
+vector.body:
+  %index = phi i64 [ 0, %entry ], [ %index.next, %vector.body ]
+  %gep = getelementptr inbounds nuw i64, ptr %a, i64 %index
+  %wide.load = load <2 x i64>, ptr %gep, align 8
+  %1 = and <2 x i64> %wide.load, %broadcast.splat
+  store <2 x i64> %1, ptr %gep, align 8
+  %index.next = add nuw i64 %index, 2
+  %2 = icmp eq i64 %index.next, 256
+  br i1 %2, label %for.cond.cleanup, label %vector.body
+
+for.cond.cleanup:
+  ret void
+}
+
+define void @array_or_not_dup_v16i8(ptr %a, i8 %m) {
+; CHECK-LABEL: array_or_not_dup_v16i8:
+; CHECK:       // %bb.0: // %entry
+; CHECK-NEXT:    mvn w8, w1
+; CHECK-NEXT:    dup v0.16b, w8
+; CHECK-NEXT:    mov x8, xzr
+; CHECK-NEXT:  .LBB223_1: // %vector.body
+; CHECK-NEXT:    // =>This Inner Loop Header: Depth=1
+; CHECK-NEXT:    ldr q1, [x0, x8]
+; CHECK-NEXT:    orr v1.16b, v1.16b, v0.16b
+; CHECK-NEXT:    str q1, [x0, x8]
+; CHECK-NEXT:    add x8, x8, #16
+; CHECK-NEXT:    cmp x8, #256
+; CHECK-NEXT:    b.ne .LBB223_1
+; CHECK-NEXT:  // %bb.2: // %for.cond.cleanup
+; CHECK-NEXT:    ret
+entry:
+  %not = xor i8 %m, -1
+  %broadcast.splatinsert = insertelement <16 x i8> poison, i8 %not, i64 0
+  %broadcast.splat = shufflevector <16 x i8> %broadcast.splatinsert, <16 x i8> poison, <16 x i32> zeroinitializer
+  br label %vector.body
+
+vector.body:
+  %index = phi i64 [ 0, %entry ], [ %index.next, %vector.body ]
+  %gep = getelementptr inbounds nuw i8, ptr %a, i64 %index
+  %wide.load = load <16 x i8>, ptr %gep, align 1
+  %1 = or <16 x i8> %wide.load, %broadcast.splat
+  store <16 x i8> %1, ptr %gep, align 1
+  %index.next = add nuw i64 %index, 16
+  %2 = icmp eq i64 %index.next, 256
+  br i1 %2, label %for.cond.cleanup, label %vector.body
+
+for.cond.cleanup:
+  ret void
+}
+
+define void @array_or_not_dup_v8i16(ptr %a, i16 %m) {
+; CHECK-LABEL: array_or_not_dup_v8i16:
+; CHECK:       // %bb.0: // %entry
+; CHECK-NEXT:    mvn w8, w1
+; CHECK-NEXT:    dup v0.8h, w8
+; CHECK-NEXT:    mov x8, xzr
+; CHECK-NEXT:  .LBB224_1: // %vector.body
+; CHECK-NEXT:    // =>This Inner Loop Header: Depth=1
+; CHECK-NEXT:    ldr q1, [x0, x8]
+; CHECK-NEXT:    orr v1.16b, v1.16b, v0.16b
+; CHECK-NEXT:    str q1, [x0, x8]
+; CHECK-NEXT:    add x8, x8, #16
+; CHECK-NEXT:    cmp x8, #512
+; CHECK-NEXT:    b.ne .LBB224_1
+; CHECK-NEXT:  // %bb.2: // %for.cond.cleanup
+; CHECK-NEXT:    ret
+entry:
+  %not = xor i16 %m, -1
+  %broadcast.splatinsert = insertelement <8 x i16> poison, i16 %not, i64 0
+  %broadcast.splat = shufflevector <8 x i16> %broadcast.splatinsert, <8 x i16> poison, <8 x i32> zeroinitializer
+  br label %vector.body
+
+vector.body:
+  %index = phi i64 [ 0, %entry ], [ %index.next, %vector.body ]
+  %gep = getelementptr inbounds nuw i16, ptr %a, i64 %index
+  %wide.load = load <8 x i16>, ptr %gep, align 2
+  %1 = or <8 x i16> %wide.load, %broadcast.splat
+  store <8 x i16> %1, ptr %gep, align 2
+  %index.next = add nuw i64 %index, 8
+  %2 = icmp eq i64 %index.next, 256
+  br i1 %2, label %for.cond.cleanup, label %vector.body
+
+for.cond.cleanup:
+  ret void
+}
+
+define void @array_or_not_dup_v4i32(ptr %a, i32 %m) {
+; CHECK-LABEL: array_or_not_dup_v4i32:
+; CHECK:       // %bb.0: // %entry
+; CHECK-NEXT:    mvn w8, w1
+; CHECK-NEXT:    dup v0.4s, w8
+; CHECK-NEXT:    mov x8, xzr
+; CHECK-NEXT:  .LBB225_1: // %vector.body
+; CHECK-NEXT:    // =>This Inner Loop Header: Depth=1
+; CHECK-NEXT:    ldr q1, [x0, x8]
+; CHECK-NEXT:    orr v1.16b, v1.16b, v0.16b
+; CHECK-NEXT:    str q1, [x0, x8]
+; CHECK-NEXT:    add x8, x8, #16
+; CHECK-NEXT:    cmp x8, #1024
+; CHECK-NEXT:    b.ne .LBB225_1
+; CHECK-NEXT:  // %bb.2: // %for.cond.cleanup
+; CHECK-NEXT:    ret
+entry:
+  %not = xor i32 %m, -1
+  %broadcast.splatinsert = insertelement <4 x i32> poison, i32 %not, i64 0
+  %broadcast.splat = shufflevector <4 x i32> %broadcast.splatinsert, <4 x i32> poison, <4 x i32> zeroinitializer
+  br label %vector.body
+
+vector.body:
+  %index = phi i64 [ 0, %entry ], [ %index.next, %vector.body ]
+  %gep = getelementptr inbounds nuw i32, ptr %a, i64 %index
+  %wide.load = load <4 x i32>, ptr %gep, align 4
+  %1 = or <4 x i32> %wide.load, %broadcast.splat
+  store <4 x i32> %1, ptr %gep, align 4
+  %index.next = add nuw i64 %index, 4
+  %2 = icmp eq i64 %index.next, 256
+  br i1 %2, label %for.cond.cleanup, label %vector.body
+
+for.cond.cleanup:
+  ret void
+}
+
+define void @array_or_not_dup_v2i64(ptr %a, i64 %m) {
+; CHECK-LABEL: array_or_not_dup_v2i64:
+; CHECK:       // %bb.0: // %entry
+; CHECK-NEXT:    mvn x8, x1
+; CHECK-NEXT:    dup v0.2d, x8
+; CHECK-NEXT:    mov x8, xzr
+; CHECK-NEXT:  .LBB226_1: // %vector.body
+; CHECK-NEXT:    // =>This Inner Loop Header: Depth=1
+; CHECK-NEXT:    ldr q1, [x0, x8]
+; CHECK-NEXT:    orr v1.16b, v1.16b, v0.16b
+; CHECK-NEXT:    str q1, [x0, x8]
+; CHECK-NEXT:    add x8, x8, #16
+; CHECK-NEXT:    cmp x8, #2048
+; CHECK-NEXT:    b.ne .LBB226_1
+; CHECK-NEXT:  // %bb.2: // %for.cond.cleanup
+; CHECK-NEXT:    ret
+entry:
+  %not = xor i64 %m, -1
+  %broadcast.splatinsert = insertelement <2 x i64> poison, i64 %not, i64 0
+  %broadcast.splat = shufflevector <2 x i64> %broadcast.splatinsert, <2 x i64> poison, <2 x i32> zeroinitializer
+  br label %vector.body
+
+vector.body:
+  %index = phi i64 [ 0, %entry ], [ %index.next, %vector.body ]
+  %gep = getelementptr inbounds nuw i64, ptr %a, i64 %index
+  %wide.load = load <2 x i64>, ptr %gep, align 8
+  %1 = or <2 x i64> %wide.load, %broadcast.splat
+  store <2 x i64> %1, ptr %gep, align 8
+  %index.next = add nuw i64 %index, 2
+  %2 = icmp eq i64 %index.next, 256
+  br i1 %2, label %for.cond.cleanup, label %vector.body
+
+for.cond.cleanup:
+  ret void
+}

>From aeb44a98a427fe4b744de5fe9ed1a4e5cbb21cde Mon Sep 17 00:00:00 2001
From: Piotr Fusik <p.fusik at samsung.com>
Date: Thu, 15 Jan 2026 15:36:34 +0100
Subject: [PATCH 2/4] [Aarch64] Sink NOT to be fold into BIC/ORN/EON

Undoes a negation being hoisted out of a loop, so that if can be fold
into an inverted bitwise operation in the loop.

Implements #108840 on AArch64
---
 .../AArch64/AArch64TargetTransformInfo.cpp    |  26 +-
 .../CodeGen/AArch64/logical-op-with-not.ll    |  84 +--
 .../AArch64/neon-bitwise-instructions.ll      | 688 +++++++++---------
 3 files changed, 405 insertions(+), 393 deletions(-)

diff --git a/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp b/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp
index b96d251a9c4d9..529846f5edbd8 100644
--- a/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp
+++ b/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp
@@ -6818,7 +6818,31 @@ bool AArch64TTIImpl::isProfitableToSinkOperands(
         Ops.push_back(&I->getOperandUse(1));
     }
     break;
-
+  case Instruction::Xor:
+    if (I->getType()->isVectorTy() && ST->hasNEON())
+      break; // NEON has no eon instruction
+    [[fallthrough]];
+  case Instruction::And:
+  case Instruction::Or:
+    for (auto &Op : I->operands()) {
+      // (and/or/xor X, (not Y)) -> (bic/orn/eon X, Y)
+      if (match(Op.get(), m_Not(m_Value()))) {
+        Ops.push_back(&Op);
+        return true;
+      }
+      // (and/or/xor X, (splat (not Y))) -> (bic/orn/eon X, (splat Y))
+      if (match(Op.get(),
+                m_Shuffle(m_InsertElt(m_Value(), m_Not(m_Value()), m_ZeroInt()),
+                          m_Value(), m_ZeroMask()))) {
+        Use &InsertElt = cast<Instruction>(Op)->getOperandUse(0);
+        Use &Not = cast<Instruction>(InsertElt)->getOperandUse(1);
+        Ops.push_back(&Not);
+        Ops.push_back(&InsertElt);
+        Ops.push_back(&Op);
+        return true;
+      }
+    }
+    break;
   default:
     break;
   }
diff --git a/llvm/test/CodeGen/AArch64/logical-op-with-not.ll b/llvm/test/CodeGen/AArch64/logical-op-with-not.ll
index 8db4ab6c8c4e9..4b35f92e6c660 100644
--- a/llvm/test/CodeGen/AArch64/logical-op-with-not.ll
+++ b/llvm/test/CodeGen/AArch64/logical-op-with-not.ll
@@ -325,12 +325,11 @@ define void @array_and_not_i8(ptr %a, i8 %m) {
 ; CHECK-LABEL: array_and_not_i8:
 ; CHECK:       // %bb.0: // %entry
 ; CHECK-NEXT:    mov x8, xzr
-; CHECK-NEXT:    mvn w9, w1
 ; CHECK-NEXT:  .LBB26_1: // %for.body
 ; CHECK-NEXT:    // =>This Inner Loop Header: Depth=1
-; CHECK-NEXT:    ldrb w10, [x0, x8]
-; CHECK-NEXT:    and w10, w10, w9
-; CHECK-NEXT:    strb w10, [x0, x8]
+; CHECK-NEXT:    ldrb w9, [x0, x8]
+; CHECK-NEXT:    bic w9, w9, w1
+; CHECK-NEXT:    strb w9, [x0, x8]
 ; CHECK-NEXT:    add x8, x8, #1
 ; CHECK-NEXT:    cmp x8, #16
 ; CHECK-NEXT:    b.ne .LBB26_1
@@ -358,12 +357,11 @@ define void @array_and_not_i16(ptr %a, i16 %m) {
 ; CHECK-LABEL: array_and_not_i16:
 ; CHECK:       // %bb.0: // %entry
 ; CHECK-NEXT:    mov x8, xzr
-; CHECK-NEXT:    mvn w9, w1
 ; CHECK-NEXT:  .LBB27_1: // %for.body
 ; CHECK-NEXT:    // =>This Inner Loop Header: Depth=1
-; CHECK-NEXT:    ldrh w10, [x0, x8]
-; CHECK-NEXT:    and w10, w10, w9
-; CHECK-NEXT:    strh w10, [x0, x8]
+; CHECK-NEXT:    ldrh w9, [x0, x8]
+; CHECK-NEXT:    bic w9, w9, w1
+; CHECK-NEXT:    strh w9, [x0, x8]
 ; CHECK-NEXT:    add x8, x8, #2
 ; CHECK-NEXT:    cmp x8, #32
 ; CHECK-NEXT:    b.ne .LBB27_1
@@ -391,12 +389,11 @@ define void @array_and_not_i32(ptr %a, i32 %m) {
 ; CHECK-LABEL: array_and_not_i32:
 ; CHECK:       // %bb.0: // %entry
 ; CHECK-NEXT:    mov x8, xzr
-; CHECK-NEXT:    mvn w9, w1
 ; CHECK-NEXT:  .LBB28_1: // %for.body
 ; CHECK-NEXT:    // =>This Inner Loop Header: Depth=1
-; CHECK-NEXT:    ldr w10, [x0, x8]
-; CHECK-NEXT:    and w10, w10, w9
-; CHECK-NEXT:    str w10, [x0, x8]
+; CHECK-NEXT:    ldr w9, [x0, x8]
+; CHECK-NEXT:    bic w9, w9, w1
+; CHECK-NEXT:    str w9, [x0, x8]
 ; CHECK-NEXT:    add x8, x8, #4
 ; CHECK-NEXT:    cmp x8, #64
 ; CHECK-NEXT:    b.ne .LBB28_1
@@ -424,12 +421,11 @@ define void @array_and_not_i64(ptr %a, i64 %m) {
 ; CHECK-LABEL: array_and_not_i64:
 ; CHECK:       // %bb.0: // %entry
 ; CHECK-NEXT:    mov x8, xzr
-; CHECK-NEXT:    mvn x9, x1
 ; CHECK-NEXT:  .LBB29_1: // %for.body
 ; CHECK-NEXT:    // =>This Inner Loop Header: Depth=1
-; CHECK-NEXT:    ldr x10, [x0, x8]
-; CHECK-NEXT:    and x10, x10, x9
-; CHECK-NEXT:    str x10, [x0, x8]
+; CHECK-NEXT:    ldr x9, [x0, x8]
+; CHECK-NEXT:    bic x9, x9, x1
+; CHECK-NEXT:    str x9, [x0, x8]
 ; CHECK-NEXT:    add x8, x8, #8
 ; CHECK-NEXT:    cmp x8, #128
 ; CHECK-NEXT:    b.ne .LBB29_1
@@ -457,12 +453,11 @@ define void @array_or_not_i8(ptr %a, i8 %m) {
 ; CHECK-LABEL: array_or_not_i8:
 ; CHECK:       // %bb.0: // %entry
 ; CHECK-NEXT:    mov x8, xzr
-; CHECK-NEXT:    mvn w9, w1
 ; CHECK-NEXT:  .LBB30_1: // %for.body
 ; CHECK-NEXT:    // =>This Inner Loop Header: Depth=1
-; CHECK-NEXT:    ldrb w10, [x0, x8]
-; CHECK-NEXT:    orr w10, w10, w9
-; CHECK-NEXT:    strb w10, [x0, x8]
+; CHECK-NEXT:    ldrb w9, [x0, x8]
+; CHECK-NEXT:    orn w9, w9, w1
+; CHECK-NEXT:    strb w9, [x0, x8]
 ; CHECK-NEXT:    add x8, x8, #1
 ; CHECK-NEXT:    cmp x8, #16
 ; CHECK-NEXT:    b.ne .LBB30_1
@@ -490,12 +485,11 @@ define void @array_or_not_i16(ptr %a, i16 %m) {
 ; CHECK-LABEL: array_or_not_i16:
 ; CHECK:       // %bb.0: // %entry
 ; CHECK-NEXT:    mov x8, xzr
-; CHECK-NEXT:    mvn w9, w1
 ; CHECK-NEXT:  .LBB31_1: // %for.body
 ; CHECK-NEXT:    // =>This Inner Loop Header: Depth=1
-; CHECK-NEXT:    ldrh w10, [x0, x8]
-; CHECK-NEXT:    orr w10, w10, w9
-; CHECK-NEXT:    strh w10, [x0, x8]
+; CHECK-NEXT:    ldrh w9, [x0, x8]
+; CHECK-NEXT:    orn w9, w9, w1
+; CHECK-NEXT:    strh w9, [x0, x8]
 ; CHECK-NEXT:    add x8, x8, #2
 ; CHECK-NEXT:    cmp x8, #32
 ; CHECK-NEXT:    b.ne .LBB31_1
@@ -523,12 +517,11 @@ define void @array_or_not_i32(ptr %a, i32 %m) {
 ; CHECK-LABEL: array_or_not_i32:
 ; CHECK:       // %bb.0: // %entry
 ; CHECK-NEXT:    mov x8, xzr
-; CHECK-NEXT:    mvn w9, w1
 ; CHECK-NEXT:  .LBB32_1: // %for.body
 ; CHECK-NEXT:    // =>This Inner Loop Header: Depth=1
-; CHECK-NEXT:    ldr w10, [x0, x8]
-; CHECK-NEXT:    orr w10, w10, w9
-; CHECK-NEXT:    str w10, [x0, x8]
+; CHECK-NEXT:    ldr w9, [x0, x8]
+; CHECK-NEXT:    orn w9, w9, w1
+; CHECK-NEXT:    str w9, [x0, x8]
 ; CHECK-NEXT:    add x8, x8, #4
 ; CHECK-NEXT:    cmp x8, #64
 ; CHECK-NEXT:    b.ne .LBB32_1
@@ -556,12 +549,11 @@ define void @array_or_not_i64(ptr %a, i64 %m) {
 ; CHECK-LABEL: array_or_not_i64:
 ; CHECK:       // %bb.0: // %entry
 ; CHECK-NEXT:    mov x8, xzr
-; CHECK-NEXT:    mvn x9, x1
 ; CHECK-NEXT:  .LBB33_1: // %for.body
 ; CHECK-NEXT:    // =>This Inner Loop Header: Depth=1
-; CHECK-NEXT:    ldr x10, [x0, x8]
-; CHECK-NEXT:    orr x10, x10, x9
-; CHECK-NEXT:    str x10, [x0, x8]
+; CHECK-NEXT:    ldr x9, [x0, x8]
+; CHECK-NEXT:    orn x9, x9, x1
+; CHECK-NEXT:    str x9, [x0, x8]
 ; CHECK-NEXT:    add x8, x8, #8
 ; CHECK-NEXT:    cmp x8, #128
 ; CHECK-NEXT:    b.ne .LBB33_1
@@ -589,12 +581,11 @@ define void @array_xor_not_i8(ptr %a, i8 %m) {
 ; CHECK-LABEL: array_xor_not_i8:
 ; CHECK:       // %bb.0: // %entry
 ; CHECK-NEXT:    mov x8, xzr
-; CHECK-NEXT:    mvn w9, w1
 ; CHECK-NEXT:  .LBB34_1: // %for.body
 ; CHECK-NEXT:    // =>This Inner Loop Header: Depth=1
-; CHECK-NEXT:    ldrb w10, [x0, x8]
-; CHECK-NEXT:    eor w10, w10, w9
-; CHECK-NEXT:    strb w10, [x0, x8]
+; CHECK-NEXT:    ldrb w9, [x0, x8]
+; CHECK-NEXT:    eon w9, w1, w9
+; CHECK-NEXT:    strb w9, [x0, x8]
 ; CHECK-NEXT:    add x8, x8, #1
 ; CHECK-NEXT:    cmp x8, #16
 ; CHECK-NEXT:    b.ne .LBB34_1
@@ -622,12 +613,11 @@ define void @array_xor_not_i16(ptr %a, i16 %m) {
 ; CHECK-LABEL: array_xor_not_i16:
 ; CHECK:       // %bb.0: // %entry
 ; CHECK-NEXT:    mov x8, xzr
-; CHECK-NEXT:    mvn w9, w1
 ; CHECK-NEXT:  .LBB35_1: // %for.body
 ; CHECK-NEXT:    // =>This Inner Loop Header: Depth=1
-; CHECK-NEXT:    ldrh w10, [x0, x8]
-; CHECK-NEXT:    eor w10, w10, w9
-; CHECK-NEXT:    strh w10, [x0, x8]
+; CHECK-NEXT:    ldrh w9, [x0, x8]
+; CHECK-NEXT:    eon w9, w1, w9
+; CHECK-NEXT:    strh w9, [x0, x8]
 ; CHECK-NEXT:    add x8, x8, #2
 ; CHECK-NEXT:    cmp x8, #32
 ; CHECK-NEXT:    b.ne .LBB35_1
@@ -655,12 +645,11 @@ define void @array_xor_not_i32(ptr %a, i32 %m) {
 ; CHECK-LABEL: array_xor_not_i32:
 ; CHECK:       // %bb.0: // %entry
 ; CHECK-NEXT:    mov x8, xzr
-; CHECK-NEXT:    mvn w9, w1
 ; CHECK-NEXT:  .LBB36_1: // %for.body
 ; CHECK-NEXT:    // =>This Inner Loop Header: Depth=1
-; CHECK-NEXT:    ldr w10, [x0, x8]
-; CHECK-NEXT:    eor w10, w10, w9
-; CHECK-NEXT:    str w10, [x0, x8]
+; CHECK-NEXT:    ldr w9, [x0, x8]
+; CHECK-NEXT:    eon w9, w1, w9
+; CHECK-NEXT:    str w9, [x0, x8]
 ; CHECK-NEXT:    add x8, x8, #4
 ; CHECK-NEXT:    cmp x8, #64
 ; CHECK-NEXT:    b.ne .LBB36_1
@@ -688,12 +677,11 @@ define void @array_xor_not_i64(ptr %a, i64 %m) {
 ; CHECK-LABEL: array_xor_not_i64:
 ; CHECK:       // %bb.0: // %entry
 ; CHECK-NEXT:    mov x8, xzr
-; CHECK-NEXT:    mvn x9, x1
 ; CHECK-NEXT:  .LBB37_1: // %for.body
 ; CHECK-NEXT:    // =>This Inner Loop Header: Depth=1
-; CHECK-NEXT:    ldr x10, [x0, x8]
-; CHECK-NEXT:    eor x10, x10, x9
-; CHECK-NEXT:    str x10, [x0, x8]
+; CHECK-NEXT:    ldr x9, [x0, x8]
+; CHECK-NEXT:    eon x9, x1, x9
+; CHECK-NEXT:    str x9, [x0, x8]
 ; CHECK-NEXT:    add x8, x8, #8
 ; CHECK-NEXT:    cmp x8, #128
 ; CHECK-NEXT:    b.ne .LBB37_1
diff --git a/llvm/test/CodeGen/AArch64/neon-bitwise-instructions.ll b/llvm/test/CodeGen/AArch64/neon-bitwise-instructions.ll
index 9c936161e5b34..63fb1296f66be 100644
--- a/llvm/test/CodeGen/AArch64/neon-bitwise-instructions.ll
+++ b/llvm/test/CodeGen/AArch64/neon-bitwise-instructions.ll
@@ -3390,34 +3390,19 @@ define <2 x i64> @or_dup_not_v2i64(<2 x i64> %a, i64 %m) {
 }
 
 define void @array_and_not_v16i8(ptr %a, <16 x i8> %m) {
-; CHECK-SD-LABEL: array_and_not_v16i8:
-; CHECK-SD:       // %bb.0: // %entry
-; CHECK-SD-NEXT:    mvn v0.16b, v0.16b
-; CHECK-SD-NEXT:    mov x8, xzr
-; CHECK-SD-NEXT:  .LBB211_1: // %vector.body
-; CHECK-SD-NEXT:    // =>This Inner Loop Header: Depth=1
-; CHECK-SD-NEXT:    ldr q1, [x0, x8]
-; CHECK-SD-NEXT:    and v1.16b, v1.16b, v0.16b
-; CHECK-SD-NEXT:    str q1, [x0, x8]
-; CHECK-SD-NEXT:    add x8, x8, #16
-; CHECK-SD-NEXT:    cmp x8, #256
-; CHECK-SD-NEXT:    b.ne .LBB211_1
-; CHECK-SD-NEXT:  // %bb.2: // %for.cond.cleanup
-; CHECK-SD-NEXT:    ret
-;
-; CHECK-GI-LABEL: array_and_not_v16i8:
-; CHECK-GI:       // %bb.0: // %entry
-; CHECK-GI-NEXT:    mov x8, xzr
-; CHECK-GI-NEXT:  .LBB211_1: // %vector.body
-; CHECK-GI-NEXT:    // =>This Inner Loop Header: Depth=1
-; CHECK-GI-NEXT:    ldr q1, [x0, x8]
-; CHECK-GI-NEXT:    bic v1.16b, v1.16b, v0.16b
-; CHECK-GI-NEXT:    str q1, [x0, x8]
-; CHECK-GI-NEXT:    add x8, x8, #16
-; CHECK-GI-NEXT:    cmp x8, #256
-; CHECK-GI-NEXT:    b.ne .LBB211_1
-; CHECK-GI-NEXT:  // %bb.2: // %for.cond.cleanup
-; CHECK-GI-NEXT:    ret
+; CHECK-LABEL: array_and_not_v16i8:
+; CHECK:       // %bb.0: // %entry
+; CHECK-NEXT:    mov x8, xzr
+; CHECK-NEXT:  .LBB211_1: // %vector.body
+; CHECK-NEXT:    // =>This Inner Loop Header: Depth=1
+; CHECK-NEXT:    ldr q1, [x0, x8]
+; CHECK-NEXT:    bic v1.16b, v1.16b, v0.16b
+; CHECK-NEXT:    str q1, [x0, x8]
+; CHECK-NEXT:    add x8, x8, #16
+; CHECK-NEXT:    cmp x8, #256
+; CHECK-NEXT:    b.ne .LBB211_1
+; CHECK-NEXT:  // %bb.2: // %for.cond.cleanup
+; CHECK-NEXT:    ret
 entry:
   %not = xor <16 x i8> %m, splat (i8 -1)
   br label %vector.body
@@ -3437,34 +3422,19 @@ for.cond.cleanup:
 }
 
 define void @array_and_not_v8i16(ptr %a, <8 x i16> %m) {
-; CHECK-SD-LABEL: array_and_not_v8i16:
-; CHECK-SD:       // %bb.0: // %entry
-; CHECK-SD-NEXT:    mvn v0.16b, v0.16b
-; CHECK-SD-NEXT:    mov x8, xzr
-; CHECK-SD-NEXT:  .LBB212_1: // %vector.body
-; CHECK-SD-NEXT:    // =>This Inner Loop Header: Depth=1
-; CHECK-SD-NEXT:    ldr q1, [x0, x8]
-; CHECK-SD-NEXT:    and v1.16b, v1.16b, v0.16b
-; CHECK-SD-NEXT:    str q1, [x0, x8]
-; CHECK-SD-NEXT:    add x8, x8, #16
-; CHECK-SD-NEXT:    cmp x8, #512
-; CHECK-SD-NEXT:    b.ne .LBB212_1
-; CHECK-SD-NEXT:  // %bb.2: // %for.cond.cleanup
-; CHECK-SD-NEXT:    ret
-;
-; CHECK-GI-LABEL: array_and_not_v8i16:
-; CHECK-GI:       // %bb.0: // %entry
-; CHECK-GI-NEXT:    mov x8, xzr
-; CHECK-GI-NEXT:  .LBB212_1: // %vector.body
-; CHECK-GI-NEXT:    // =>This Inner Loop Header: Depth=1
-; CHECK-GI-NEXT:    ldr q1, [x0, x8]
-; CHECK-GI-NEXT:    bic v1.16b, v1.16b, v0.16b
-; CHECK-GI-NEXT:    str q1, [x0, x8]
-; CHECK-GI-NEXT:    add x8, x8, #16
-; CHECK-GI-NEXT:    cmp x8, #512
-; CHECK-GI-NEXT:    b.ne .LBB212_1
-; CHECK-GI-NEXT:  // %bb.2: // %for.cond.cleanup
-; CHECK-GI-NEXT:    ret
+; CHECK-LABEL: array_and_not_v8i16:
+; CHECK:       // %bb.0: // %entry
+; CHECK-NEXT:    mov x8, xzr
+; CHECK-NEXT:  .LBB212_1: // %vector.body
+; CHECK-NEXT:    // =>This Inner Loop Header: Depth=1
+; CHECK-NEXT:    ldr q1, [x0, x8]
+; CHECK-NEXT:    bic v1.16b, v1.16b, v0.16b
+; CHECK-NEXT:    str q1, [x0, x8]
+; CHECK-NEXT:    add x8, x8, #16
+; CHECK-NEXT:    cmp x8, #512
+; CHECK-NEXT:    b.ne .LBB212_1
+; CHECK-NEXT:  // %bb.2: // %for.cond.cleanup
+; CHECK-NEXT:    ret
 entry:
   %not = xor <8 x i16> %m, splat (i16 -1)
   br label %vector.body
@@ -3484,34 +3454,19 @@ for.cond.cleanup:
 }
 
 define void @array_and_not_v4i32(ptr %a, <4 x i32> %m) {
-; CHECK-SD-LABEL: array_and_not_v4i32:
-; CHECK-SD:       // %bb.0: // %entry
-; CHECK-SD-NEXT:    mvn v0.16b, v0.16b
-; CHECK-SD-NEXT:    mov x8, xzr
-; CHECK-SD-NEXT:  .LBB213_1: // %vector.body
-; CHECK-SD-NEXT:    // =>This Inner Loop Header: Depth=1
-; CHECK-SD-NEXT:    ldr q1, [x0, x8]
-; CHECK-SD-NEXT:    and v1.16b, v1.16b, v0.16b
-; CHECK-SD-NEXT:    str q1, [x0, x8]
-; CHECK-SD-NEXT:    add x8, x8, #16
-; CHECK-SD-NEXT:    cmp x8, #1024
-; CHECK-SD-NEXT:    b.ne .LBB213_1
-; CHECK-SD-NEXT:  // %bb.2: // %for.cond.cleanup
-; CHECK-SD-NEXT:    ret
-;
-; CHECK-GI-LABEL: array_and_not_v4i32:
-; CHECK-GI:       // %bb.0: // %entry
-; CHECK-GI-NEXT:    mov x8, xzr
-; CHECK-GI-NEXT:  .LBB213_1: // %vector.body
-; CHECK-GI-NEXT:    // =>This Inner Loop Header: Depth=1
-; CHECK-GI-NEXT:    ldr q1, [x0, x8]
-; CHECK-GI-NEXT:    bic v1.16b, v1.16b, v0.16b
-; CHECK-GI-NEXT:    str q1, [x0, x8]
-; CHECK-GI-NEXT:    add x8, x8, #16
-; CHECK-GI-NEXT:    cmp x8, #1024
-; CHECK-GI-NEXT:    b.ne .LBB213_1
-; CHECK-GI-NEXT:  // %bb.2: // %for.cond.cleanup
-; CHECK-GI-NEXT:    ret
+; CHECK-LABEL: array_and_not_v4i32:
+; CHECK:       // %bb.0: // %entry
+; CHECK-NEXT:    mov x8, xzr
+; CHECK-NEXT:  .LBB213_1: // %vector.body
+; CHECK-NEXT:    // =>This Inner Loop Header: Depth=1
+; CHECK-NEXT:    ldr q1, [x0, x8]
+; CHECK-NEXT:    bic v1.16b, v1.16b, v0.16b
+; CHECK-NEXT:    str q1, [x0, x8]
+; CHECK-NEXT:    add x8, x8, #16
+; CHECK-NEXT:    cmp x8, #1024
+; CHECK-NEXT:    b.ne .LBB213_1
+; CHECK-NEXT:  // %bb.2: // %for.cond.cleanup
+; CHECK-NEXT:    ret
 entry:
   %not = xor <4 x i32> %m, splat (i32 -1)
   br label %vector.body
@@ -3531,34 +3486,19 @@ for.cond.cleanup:
 }
 
 define void @array_and_not_v2i64(ptr %a, <2 x i64> %m) {
-; CHECK-SD-LABEL: array_and_not_v2i64:
-; CHECK-SD:       // %bb.0: // %entry
-; CHECK-SD-NEXT:    mvn v0.16b, v0.16b
-; CHECK-SD-NEXT:    mov x8, xzr
-; CHECK-SD-NEXT:  .LBB214_1: // %vector.body
-; CHECK-SD-NEXT:    // =>This Inner Loop Header: Depth=1
-; CHECK-SD-NEXT:    ldr q1, [x0, x8]
-; CHECK-SD-NEXT:    and v1.16b, v1.16b, v0.16b
-; CHECK-SD-NEXT:    str q1, [x0, x8]
-; CHECK-SD-NEXT:    add x8, x8, #16
-; CHECK-SD-NEXT:    cmp x8, #2048
-; CHECK-SD-NEXT:    b.ne .LBB214_1
-; CHECK-SD-NEXT:  // %bb.2: // %for.cond.cleanup
-; CHECK-SD-NEXT:    ret
-;
-; CHECK-GI-LABEL: array_and_not_v2i64:
-; CHECK-GI:       // %bb.0: // %entry
-; CHECK-GI-NEXT:    mov x8, xzr
-; CHECK-GI-NEXT:  .LBB214_1: // %vector.body
-; CHECK-GI-NEXT:    // =>This Inner Loop Header: Depth=1
-; CHECK-GI-NEXT:    ldr q1, [x0, x8]
-; CHECK-GI-NEXT:    bic v1.16b, v1.16b, v0.16b
-; CHECK-GI-NEXT:    str q1, [x0, x8]
-; CHECK-GI-NEXT:    add x8, x8, #16
-; CHECK-GI-NEXT:    cmp x8, #2048
-; CHECK-GI-NEXT:    b.ne .LBB214_1
-; CHECK-GI-NEXT:  // %bb.2: // %for.cond.cleanup
-; CHECK-GI-NEXT:    ret
+; CHECK-LABEL: array_and_not_v2i64:
+; CHECK:       // %bb.0: // %entry
+; CHECK-NEXT:    mov x8, xzr
+; CHECK-NEXT:  .LBB214_1: // %vector.body
+; CHECK-NEXT:    // =>This Inner Loop Header: Depth=1
+; CHECK-NEXT:    ldr q1, [x0, x8]
+; CHECK-NEXT:    bic v1.16b, v1.16b, v0.16b
+; CHECK-NEXT:    str q1, [x0, x8]
+; CHECK-NEXT:    add x8, x8, #16
+; CHECK-NEXT:    cmp x8, #2048
+; CHECK-NEXT:    b.ne .LBB214_1
+; CHECK-NEXT:  // %bb.2: // %for.cond.cleanup
+; CHECK-NEXT:    ret
 entry:
   %not = xor <2 x i64> %m, splat (i64 -1)
   br label %vector.body
@@ -3578,34 +3518,19 @@ for.cond.cleanup:
 }
 
 define void @array_or_not_v16i8(ptr %a, <16 x i8> %m) {
-; CHECK-SD-LABEL: array_or_not_v16i8:
-; CHECK-SD:       // %bb.0: // %entry
-; CHECK-SD-NEXT:    mvn v0.16b, v0.16b
-; CHECK-SD-NEXT:    mov x8, xzr
-; CHECK-SD-NEXT:  .LBB215_1: // %vector.body
-; CHECK-SD-NEXT:    // =>This Inner Loop Header: Depth=1
-; CHECK-SD-NEXT:    ldr q1, [x0, x8]
-; CHECK-SD-NEXT:    orr v1.16b, v1.16b, v0.16b
-; CHECK-SD-NEXT:    str q1, [x0, x8]
-; CHECK-SD-NEXT:    add x8, x8, #16
-; CHECK-SD-NEXT:    cmp x8, #256
-; CHECK-SD-NEXT:    b.ne .LBB215_1
-; CHECK-SD-NEXT:  // %bb.2: // %for.cond.cleanup
-; CHECK-SD-NEXT:    ret
-;
-; CHECK-GI-LABEL: array_or_not_v16i8:
-; CHECK-GI:       // %bb.0: // %entry
-; CHECK-GI-NEXT:    mov x8, xzr
-; CHECK-GI-NEXT:  .LBB215_1: // %vector.body
-; CHECK-GI-NEXT:    // =>This Inner Loop Header: Depth=1
-; CHECK-GI-NEXT:    ldr q1, [x0, x8]
-; CHECK-GI-NEXT:    orn v1.16b, v1.16b, v0.16b
-; CHECK-GI-NEXT:    str q1, [x0, x8]
-; CHECK-GI-NEXT:    add x8, x8, #16
-; CHECK-GI-NEXT:    cmp x8, #256
-; CHECK-GI-NEXT:    b.ne .LBB215_1
-; CHECK-GI-NEXT:  // %bb.2: // %for.cond.cleanup
-; CHECK-GI-NEXT:    ret
+; CHECK-LABEL: array_or_not_v16i8:
+; CHECK:       // %bb.0: // %entry
+; CHECK-NEXT:    mov x8, xzr
+; CHECK-NEXT:  .LBB215_1: // %vector.body
+; CHECK-NEXT:    // =>This Inner Loop Header: Depth=1
+; CHECK-NEXT:    ldr q1, [x0, x8]
+; CHECK-NEXT:    orn v1.16b, v1.16b, v0.16b
+; CHECK-NEXT:    str q1, [x0, x8]
+; CHECK-NEXT:    add x8, x8, #16
+; CHECK-NEXT:    cmp x8, #256
+; CHECK-NEXT:    b.ne .LBB215_1
+; CHECK-NEXT:  // %bb.2: // %for.cond.cleanup
+; CHECK-NEXT:    ret
 entry:
   %not = xor <16 x i8> %m, splat (i8 -1)
   br label %vector.body
@@ -3625,34 +3550,19 @@ for.cond.cleanup:
 }
 
 define void @array_or_not_v8i16(ptr %a, <8 x i16> %m) {
-; CHECK-SD-LABEL: array_or_not_v8i16:
-; CHECK-SD:       // %bb.0: // %entry
-; CHECK-SD-NEXT:    mvn v0.16b, v0.16b
-; CHECK-SD-NEXT:    mov x8, xzr
-; CHECK-SD-NEXT:  .LBB216_1: // %vector.body
-; CHECK-SD-NEXT:    // =>This Inner Loop Header: Depth=1
-; CHECK-SD-NEXT:    ldr q1, [x0, x8]
-; CHECK-SD-NEXT:    orr v1.16b, v1.16b, v0.16b
-; CHECK-SD-NEXT:    str q1, [x0, x8]
-; CHECK-SD-NEXT:    add x8, x8, #16
-; CHECK-SD-NEXT:    cmp x8, #512
-; CHECK-SD-NEXT:    b.ne .LBB216_1
-; CHECK-SD-NEXT:  // %bb.2: // %for.cond.cleanup
-; CHECK-SD-NEXT:    ret
-;
-; CHECK-GI-LABEL: array_or_not_v8i16:
-; CHECK-GI:       // %bb.0: // %entry
-; CHECK-GI-NEXT:    mov x8, xzr
-; CHECK-GI-NEXT:  .LBB216_1: // %vector.body
-; CHECK-GI-NEXT:    // =>This Inner Loop Header: Depth=1
-; CHECK-GI-NEXT:    ldr q1, [x0, x8]
-; CHECK-GI-NEXT:    orn v1.16b, v1.16b, v0.16b
-; CHECK-GI-NEXT:    str q1, [x0, x8]
-; CHECK-GI-NEXT:    add x8, x8, #16
-; CHECK-GI-NEXT:    cmp x8, #512
-; CHECK-GI-NEXT:    b.ne .LBB216_1
-; CHECK-GI-NEXT:  // %bb.2: // %for.cond.cleanup
-; CHECK-GI-NEXT:    ret
+; CHECK-LABEL: array_or_not_v8i16:
+; CHECK:       // %bb.0: // %entry
+; CHECK-NEXT:    mov x8, xzr
+; CHECK-NEXT:  .LBB216_1: // %vector.body
+; CHECK-NEXT:    // =>This Inner Loop Header: Depth=1
+; CHECK-NEXT:    ldr q1, [x0, x8]
+; CHECK-NEXT:    orn v1.16b, v1.16b, v0.16b
+; CHECK-NEXT:    str q1, [x0, x8]
+; CHECK-NEXT:    add x8, x8, #16
+; CHECK-NEXT:    cmp x8, #512
+; CHECK-NEXT:    b.ne .LBB216_1
+; CHECK-NEXT:  // %bb.2: // %for.cond.cleanup
+; CHECK-NEXT:    ret
 entry:
   %not = xor <8 x i16> %m, splat (i16 -1)
   br label %vector.body
@@ -3672,34 +3582,19 @@ for.cond.cleanup:
 }
 
 define void @array_or_not_v4i32(ptr %a, <4 x i32> %m) {
-; CHECK-SD-LABEL: array_or_not_v4i32:
-; CHECK-SD:       // %bb.0: // %entry
-; CHECK-SD-NEXT:    mvn v0.16b, v0.16b
-; CHECK-SD-NEXT:    mov x8, xzr
-; CHECK-SD-NEXT:  .LBB217_1: // %vector.body
-; CHECK-SD-NEXT:    // =>This Inner Loop Header: Depth=1
-; CHECK-SD-NEXT:    ldr q1, [x0, x8]
-; CHECK-SD-NEXT:    orr v1.16b, v1.16b, v0.16b
-; CHECK-SD-NEXT:    str q1, [x0, x8]
-; CHECK-SD-NEXT:    add x8, x8, #16
-; CHECK-SD-NEXT:    cmp x8, #1024
-; CHECK-SD-NEXT:    b.ne .LBB217_1
-; CHECK-SD-NEXT:  // %bb.2: // %for.cond.cleanup
-; CHECK-SD-NEXT:    ret
-;
-; CHECK-GI-LABEL: array_or_not_v4i32:
-; CHECK-GI:       // %bb.0: // %entry
-; CHECK-GI-NEXT:    mov x8, xzr
-; CHECK-GI-NEXT:  .LBB217_1: // %vector.body
-; CHECK-GI-NEXT:    // =>This Inner Loop Header: Depth=1
-; CHECK-GI-NEXT:    ldr q1, [x0, x8]
-; CHECK-GI-NEXT:    orn v1.16b, v1.16b, v0.16b
-; CHECK-GI-NEXT:    str q1, [x0, x8]
-; CHECK-GI-NEXT:    add x8, x8, #16
-; CHECK-GI-NEXT:    cmp x8, #1024
-; CHECK-GI-NEXT:    b.ne .LBB217_1
-; CHECK-GI-NEXT:  // %bb.2: // %for.cond.cleanup
-; CHECK-GI-NEXT:    ret
+; CHECK-LABEL: array_or_not_v4i32:
+; CHECK:       // %bb.0: // %entry
+; CHECK-NEXT:    mov x8, xzr
+; CHECK-NEXT:  .LBB217_1: // %vector.body
+; CHECK-NEXT:    // =>This Inner Loop Header: Depth=1
+; CHECK-NEXT:    ldr q1, [x0, x8]
+; CHECK-NEXT:    orn v1.16b, v1.16b, v0.16b
+; CHECK-NEXT:    str q1, [x0, x8]
+; CHECK-NEXT:    add x8, x8, #16
+; CHECK-NEXT:    cmp x8, #1024
+; CHECK-NEXT:    b.ne .LBB217_1
+; CHECK-NEXT:  // %bb.2: // %for.cond.cleanup
+; CHECK-NEXT:    ret
 entry:
   %not = xor <4 x i32> %m, splat (i32 -1)
   br label %vector.body
@@ -3719,34 +3614,19 @@ for.cond.cleanup:
 }
 
 define void @array_or_not_v2i64(ptr %a, <2 x i64> %m) {
-; CHECK-SD-LABEL: array_or_not_v2i64:
-; CHECK-SD:       // %bb.0: // %entry
-; CHECK-SD-NEXT:    mvn v0.16b, v0.16b
-; CHECK-SD-NEXT:    mov x8, xzr
-; CHECK-SD-NEXT:  .LBB218_1: // %vector.body
-; CHECK-SD-NEXT:    // =>This Inner Loop Header: Depth=1
-; CHECK-SD-NEXT:    ldr q1, [x0, x8]
-; CHECK-SD-NEXT:    orr v1.16b, v1.16b, v0.16b
-; CHECK-SD-NEXT:    str q1, [x0, x8]
-; CHECK-SD-NEXT:    add x8, x8, #16
-; CHECK-SD-NEXT:    cmp x8, #2048
-; CHECK-SD-NEXT:    b.ne .LBB218_1
-; CHECK-SD-NEXT:  // %bb.2: // %for.cond.cleanup
-; CHECK-SD-NEXT:    ret
-;
-; CHECK-GI-LABEL: array_or_not_v2i64:
-; CHECK-GI:       // %bb.0: // %entry
-; CHECK-GI-NEXT:    mov x8, xzr
-; CHECK-GI-NEXT:  .LBB218_1: // %vector.body
-; CHECK-GI-NEXT:    // =>This Inner Loop Header: Depth=1
-; CHECK-GI-NEXT:    ldr q1, [x0, x8]
-; CHECK-GI-NEXT:    orn v1.16b, v1.16b, v0.16b
-; CHECK-GI-NEXT:    str q1, [x0, x8]
-; CHECK-GI-NEXT:    add x8, x8, #16
-; CHECK-GI-NEXT:    cmp x8, #2048
-; CHECK-GI-NEXT:    b.ne .LBB218_1
-; CHECK-GI-NEXT:  // %bb.2: // %for.cond.cleanup
-; CHECK-GI-NEXT:    ret
+; CHECK-LABEL: array_or_not_v2i64:
+; CHECK:       // %bb.0: // %entry
+; CHECK-NEXT:    mov x8, xzr
+; CHECK-NEXT:  .LBB218_1: // %vector.body
+; CHECK-NEXT:    // =>This Inner Loop Header: Depth=1
+; CHECK-NEXT:    ldr q1, [x0, x8]
+; CHECK-NEXT:    orn v1.16b, v1.16b, v0.16b
+; CHECK-NEXT:    str q1, [x0, x8]
+; CHECK-NEXT:    add x8, x8, #16
+; CHECK-NEXT:    cmp x8, #2048
+; CHECK-NEXT:    b.ne .LBB218_1
+; CHECK-NEXT:  // %bb.2: // %for.cond.cleanup
+; CHECK-NEXT:    ret
 entry:
   %not = xor <2 x i64> %m, splat (i64 -1)
   br label %vector.body
@@ -3766,21 +3646,36 @@ for.cond.cleanup:
 }
 
 define void @array_and_not_dup_v16i8(ptr %a, i8 %m) {
-; CHECK-LABEL: array_and_not_dup_v16i8:
-; CHECK:       // %bb.0: // %entry
-; CHECK-NEXT:    mvn w8, w1
-; CHECK-NEXT:    dup v0.16b, w8
-; CHECK-NEXT:    mov x8, xzr
-; CHECK-NEXT:  .LBB219_1: // %vector.body
-; CHECK-NEXT:    // =>This Inner Loop Header: Depth=1
-; CHECK-NEXT:    ldr q1, [x0, x8]
-; CHECK-NEXT:    and v1.16b, v1.16b, v0.16b
-; CHECK-NEXT:    str q1, [x0, x8]
-; CHECK-NEXT:    add x8, x8, #16
-; CHECK-NEXT:    cmp x8, #256
-; CHECK-NEXT:    b.ne .LBB219_1
-; CHECK-NEXT:  // %bb.2: // %for.cond.cleanup
-; CHECK-NEXT:    ret
+; CHECK-SD-LABEL: array_and_not_dup_v16i8:
+; CHECK-SD:       // %bb.0: // %entry
+; CHECK-SD-NEXT:    dup v0.16b, w1
+; CHECK-SD-NEXT:    mov x8, xzr
+; CHECK-SD-NEXT:  .LBB219_1: // %vector.body
+; CHECK-SD-NEXT:    // =>This Inner Loop Header: Depth=1
+; CHECK-SD-NEXT:    ldr q1, [x0, x8]
+; CHECK-SD-NEXT:    bic v1.16b, v1.16b, v0.16b
+; CHECK-SD-NEXT:    str q1, [x0, x8]
+; CHECK-SD-NEXT:    add x8, x8, #16
+; CHECK-SD-NEXT:    cmp x8, #256
+; CHECK-SD-NEXT:    b.ne .LBB219_1
+; CHECK-SD-NEXT:  // %bb.2: // %for.cond.cleanup
+; CHECK-SD-NEXT:    ret
+;
+; CHECK-GI-LABEL: array_and_not_dup_v16i8:
+; CHECK-GI:       // %bb.0: // %entry
+; CHECK-GI-NEXT:    mvn w8, w1
+; CHECK-GI-NEXT:    dup v0.16b, w8
+; CHECK-GI-NEXT:    mov x8, xzr
+; CHECK-GI-NEXT:  .LBB219_1: // %vector.body
+; CHECK-GI-NEXT:    // =>This Inner Loop Header: Depth=1
+; CHECK-GI-NEXT:    ldr q1, [x0, x8]
+; CHECK-GI-NEXT:    and v1.16b, v1.16b, v0.16b
+; CHECK-GI-NEXT:    str q1, [x0, x8]
+; CHECK-GI-NEXT:    add x8, x8, #16
+; CHECK-GI-NEXT:    cmp x8, #256
+; CHECK-GI-NEXT:    b.ne .LBB219_1
+; CHECK-GI-NEXT:  // %bb.2: // %for.cond.cleanup
+; CHECK-GI-NEXT:    ret
 entry:
   %not = xor i8 %m, -1
   %broadcast.splatinsert = insertelement <16 x i8> poison, i8 %not, i64 0
@@ -3802,21 +3697,36 @@ for.cond.cleanup:
 }
 
 define void @array_and_not_dup_v8i16(ptr %a, i16 %m) {
-; CHECK-LABEL: array_and_not_dup_v8i16:
-; CHECK:       // %bb.0: // %entry
-; CHECK-NEXT:    mvn w8, w1
-; CHECK-NEXT:    dup v0.8h, w8
-; CHECK-NEXT:    mov x8, xzr
-; CHECK-NEXT:  .LBB220_1: // %vector.body
-; CHECK-NEXT:    // =>This Inner Loop Header: Depth=1
-; CHECK-NEXT:    ldr q1, [x0, x8]
-; CHECK-NEXT:    and v1.16b, v1.16b, v0.16b
-; CHECK-NEXT:    str q1, [x0, x8]
-; CHECK-NEXT:    add x8, x8, #16
-; CHECK-NEXT:    cmp x8, #512
-; CHECK-NEXT:    b.ne .LBB220_1
-; CHECK-NEXT:  // %bb.2: // %for.cond.cleanup
-; CHECK-NEXT:    ret
+; CHECK-SD-LABEL: array_and_not_dup_v8i16:
+; CHECK-SD:       // %bb.0: // %entry
+; CHECK-SD-NEXT:    dup v0.8h, w1
+; CHECK-SD-NEXT:    mov x8, xzr
+; CHECK-SD-NEXT:  .LBB220_1: // %vector.body
+; CHECK-SD-NEXT:    // =>This Inner Loop Header: Depth=1
+; CHECK-SD-NEXT:    ldr q1, [x0, x8]
+; CHECK-SD-NEXT:    bic v1.16b, v1.16b, v0.16b
+; CHECK-SD-NEXT:    str q1, [x0, x8]
+; CHECK-SD-NEXT:    add x8, x8, #16
+; CHECK-SD-NEXT:    cmp x8, #512
+; CHECK-SD-NEXT:    b.ne .LBB220_1
+; CHECK-SD-NEXT:  // %bb.2: // %for.cond.cleanup
+; CHECK-SD-NEXT:    ret
+;
+; CHECK-GI-LABEL: array_and_not_dup_v8i16:
+; CHECK-GI:       // %bb.0: // %entry
+; CHECK-GI-NEXT:    mvn w8, w1
+; CHECK-GI-NEXT:    dup v0.8h, w8
+; CHECK-GI-NEXT:    mov x8, xzr
+; CHECK-GI-NEXT:  .LBB220_1: // %vector.body
+; CHECK-GI-NEXT:    // =>This Inner Loop Header: Depth=1
+; CHECK-GI-NEXT:    ldr q1, [x0, x8]
+; CHECK-GI-NEXT:    and v1.16b, v1.16b, v0.16b
+; CHECK-GI-NEXT:    str q1, [x0, x8]
+; CHECK-GI-NEXT:    add x8, x8, #16
+; CHECK-GI-NEXT:    cmp x8, #512
+; CHECK-GI-NEXT:    b.ne .LBB220_1
+; CHECK-GI-NEXT:  // %bb.2: // %for.cond.cleanup
+; CHECK-GI-NEXT:    ret
 entry:
   %not = xor i16 %m, -1
   %broadcast.splatinsert = insertelement <8 x i16> poison, i16 %not, i64 0
@@ -3838,21 +3748,36 @@ for.cond.cleanup:
 }
 
 define void @array_and_not_dup_v4i32(ptr %a, i32 %m) {
-; CHECK-LABEL: array_and_not_dup_v4i32:
-; CHECK:       // %bb.0: // %entry
-; CHECK-NEXT:    mvn w8, w1
-; CHECK-NEXT:    dup v0.4s, w8
-; CHECK-NEXT:    mov x8, xzr
-; CHECK-NEXT:  .LBB221_1: // %vector.body
-; CHECK-NEXT:    // =>This Inner Loop Header: Depth=1
-; CHECK-NEXT:    ldr q1, [x0, x8]
-; CHECK-NEXT:    and v1.16b, v1.16b, v0.16b
-; CHECK-NEXT:    str q1, [x0, x8]
-; CHECK-NEXT:    add x8, x8, #16
-; CHECK-NEXT:    cmp x8, #1024
-; CHECK-NEXT:    b.ne .LBB221_1
-; CHECK-NEXT:  // %bb.2: // %for.cond.cleanup
-; CHECK-NEXT:    ret
+; CHECK-SD-LABEL: array_and_not_dup_v4i32:
+; CHECK-SD:       // %bb.0: // %entry
+; CHECK-SD-NEXT:    dup v0.4s, w1
+; CHECK-SD-NEXT:    mov x8, xzr
+; CHECK-SD-NEXT:  .LBB221_1: // %vector.body
+; CHECK-SD-NEXT:    // =>This Inner Loop Header: Depth=1
+; CHECK-SD-NEXT:    ldr q1, [x0, x8]
+; CHECK-SD-NEXT:    bic v1.16b, v1.16b, v0.16b
+; CHECK-SD-NEXT:    str q1, [x0, x8]
+; CHECK-SD-NEXT:    add x8, x8, #16
+; CHECK-SD-NEXT:    cmp x8, #1024
+; CHECK-SD-NEXT:    b.ne .LBB221_1
+; CHECK-SD-NEXT:  // %bb.2: // %for.cond.cleanup
+; CHECK-SD-NEXT:    ret
+;
+; CHECK-GI-LABEL: array_and_not_dup_v4i32:
+; CHECK-GI:       // %bb.0: // %entry
+; CHECK-GI-NEXT:    mvn w8, w1
+; CHECK-GI-NEXT:    dup v0.4s, w8
+; CHECK-GI-NEXT:    mov x8, xzr
+; CHECK-GI-NEXT:  .LBB221_1: // %vector.body
+; CHECK-GI-NEXT:    // =>This Inner Loop Header: Depth=1
+; CHECK-GI-NEXT:    ldr q1, [x0, x8]
+; CHECK-GI-NEXT:    and v1.16b, v1.16b, v0.16b
+; CHECK-GI-NEXT:    str q1, [x0, x8]
+; CHECK-GI-NEXT:    add x8, x8, #16
+; CHECK-GI-NEXT:    cmp x8, #1024
+; CHECK-GI-NEXT:    b.ne .LBB221_1
+; CHECK-GI-NEXT:  // %bb.2: // %for.cond.cleanup
+; CHECK-GI-NEXT:    ret
 entry:
   %not = xor i32 %m, -1
   %broadcast.splatinsert = insertelement <4 x i32> poison, i32 %not, i64 0
@@ -3874,21 +3799,36 @@ for.cond.cleanup:
 }
 
 define void @array_and_not_dup_v2i64(ptr %a, i64 %m) {
-; CHECK-LABEL: array_and_not_dup_v2i64:
-; CHECK:       // %bb.0: // %entry
-; CHECK-NEXT:    mvn x8, x1
-; CHECK-NEXT:    dup v0.2d, x8
-; CHECK-NEXT:    mov x8, xzr
-; CHECK-NEXT:  .LBB222_1: // %vector.body
-; CHECK-NEXT:    // =>This Inner Loop Header: Depth=1
-; CHECK-NEXT:    ldr q1, [x0, x8]
-; CHECK-NEXT:    and v1.16b, v1.16b, v0.16b
-; CHECK-NEXT:    str q1, [x0, x8]
-; CHECK-NEXT:    add x8, x8, #16
-; CHECK-NEXT:    cmp x8, #2048
-; CHECK-NEXT:    b.ne .LBB222_1
-; CHECK-NEXT:  // %bb.2: // %for.cond.cleanup
-; CHECK-NEXT:    ret
+; CHECK-SD-LABEL: array_and_not_dup_v2i64:
+; CHECK-SD:       // %bb.0: // %entry
+; CHECK-SD-NEXT:    dup v0.2d, x1
+; CHECK-SD-NEXT:    mov x8, xzr
+; CHECK-SD-NEXT:  .LBB222_1: // %vector.body
+; CHECK-SD-NEXT:    // =>This Inner Loop Header: Depth=1
+; CHECK-SD-NEXT:    ldr q1, [x0, x8]
+; CHECK-SD-NEXT:    bic v1.16b, v1.16b, v0.16b
+; CHECK-SD-NEXT:    str q1, [x0, x8]
+; CHECK-SD-NEXT:    add x8, x8, #16
+; CHECK-SD-NEXT:    cmp x8, #2048
+; CHECK-SD-NEXT:    b.ne .LBB222_1
+; CHECK-SD-NEXT:  // %bb.2: // %for.cond.cleanup
+; CHECK-SD-NEXT:    ret
+;
+; CHECK-GI-LABEL: array_and_not_dup_v2i64:
+; CHECK-GI:       // %bb.0: // %entry
+; CHECK-GI-NEXT:    mvn x8, x1
+; CHECK-GI-NEXT:    dup v0.2d, x8
+; CHECK-GI-NEXT:    mov x8, xzr
+; CHECK-GI-NEXT:  .LBB222_1: // %vector.body
+; CHECK-GI-NEXT:    // =>This Inner Loop Header: Depth=1
+; CHECK-GI-NEXT:    ldr q1, [x0, x8]
+; CHECK-GI-NEXT:    and v1.16b, v1.16b, v0.16b
+; CHECK-GI-NEXT:    str q1, [x0, x8]
+; CHECK-GI-NEXT:    add x8, x8, #16
+; CHECK-GI-NEXT:    cmp x8, #2048
+; CHECK-GI-NEXT:    b.ne .LBB222_1
+; CHECK-GI-NEXT:  // %bb.2: // %for.cond.cleanup
+; CHECK-GI-NEXT:    ret
 entry:
   %not = xor i64 %m, -1
   %broadcast.splatinsert = insertelement <2 x i64> poison, i64 %not, i64 0
@@ -3910,21 +3850,36 @@ for.cond.cleanup:
 }
 
 define void @array_or_not_dup_v16i8(ptr %a, i8 %m) {
-; CHECK-LABEL: array_or_not_dup_v16i8:
-; CHECK:       // %bb.0: // %entry
-; CHECK-NEXT:    mvn w8, w1
-; CHECK-NEXT:    dup v0.16b, w8
-; CHECK-NEXT:    mov x8, xzr
-; CHECK-NEXT:  .LBB223_1: // %vector.body
-; CHECK-NEXT:    // =>This Inner Loop Header: Depth=1
-; CHECK-NEXT:    ldr q1, [x0, x8]
-; CHECK-NEXT:    orr v1.16b, v1.16b, v0.16b
-; CHECK-NEXT:    str q1, [x0, x8]
-; CHECK-NEXT:    add x8, x8, #16
-; CHECK-NEXT:    cmp x8, #256
-; CHECK-NEXT:    b.ne .LBB223_1
-; CHECK-NEXT:  // %bb.2: // %for.cond.cleanup
-; CHECK-NEXT:    ret
+; CHECK-SD-LABEL: array_or_not_dup_v16i8:
+; CHECK-SD:       // %bb.0: // %entry
+; CHECK-SD-NEXT:    dup v0.16b, w1
+; CHECK-SD-NEXT:    mov x8, xzr
+; CHECK-SD-NEXT:  .LBB223_1: // %vector.body
+; CHECK-SD-NEXT:    // =>This Inner Loop Header: Depth=1
+; CHECK-SD-NEXT:    ldr q1, [x0, x8]
+; CHECK-SD-NEXT:    orn v1.16b, v1.16b, v0.16b
+; CHECK-SD-NEXT:    str q1, [x0, x8]
+; CHECK-SD-NEXT:    add x8, x8, #16
+; CHECK-SD-NEXT:    cmp x8, #256
+; CHECK-SD-NEXT:    b.ne .LBB223_1
+; CHECK-SD-NEXT:  // %bb.2: // %for.cond.cleanup
+; CHECK-SD-NEXT:    ret
+;
+; CHECK-GI-LABEL: array_or_not_dup_v16i8:
+; CHECK-GI:       // %bb.0: // %entry
+; CHECK-GI-NEXT:    mvn w8, w1
+; CHECK-GI-NEXT:    dup v0.16b, w8
+; CHECK-GI-NEXT:    mov x8, xzr
+; CHECK-GI-NEXT:  .LBB223_1: // %vector.body
+; CHECK-GI-NEXT:    // =>This Inner Loop Header: Depth=1
+; CHECK-GI-NEXT:    ldr q1, [x0, x8]
+; CHECK-GI-NEXT:    orr v1.16b, v1.16b, v0.16b
+; CHECK-GI-NEXT:    str q1, [x0, x8]
+; CHECK-GI-NEXT:    add x8, x8, #16
+; CHECK-GI-NEXT:    cmp x8, #256
+; CHECK-GI-NEXT:    b.ne .LBB223_1
+; CHECK-GI-NEXT:  // %bb.2: // %for.cond.cleanup
+; CHECK-GI-NEXT:    ret
 entry:
   %not = xor i8 %m, -1
   %broadcast.splatinsert = insertelement <16 x i8> poison, i8 %not, i64 0
@@ -3946,21 +3901,36 @@ for.cond.cleanup:
 }
 
 define void @array_or_not_dup_v8i16(ptr %a, i16 %m) {
-; CHECK-LABEL: array_or_not_dup_v8i16:
-; CHECK:       // %bb.0: // %entry
-; CHECK-NEXT:    mvn w8, w1
-; CHECK-NEXT:    dup v0.8h, w8
-; CHECK-NEXT:    mov x8, xzr
-; CHECK-NEXT:  .LBB224_1: // %vector.body
-; CHECK-NEXT:    // =>This Inner Loop Header: Depth=1
-; CHECK-NEXT:    ldr q1, [x0, x8]
-; CHECK-NEXT:    orr v1.16b, v1.16b, v0.16b
-; CHECK-NEXT:    str q1, [x0, x8]
-; CHECK-NEXT:    add x8, x8, #16
-; CHECK-NEXT:    cmp x8, #512
-; CHECK-NEXT:    b.ne .LBB224_1
-; CHECK-NEXT:  // %bb.2: // %for.cond.cleanup
-; CHECK-NEXT:    ret
+; CHECK-SD-LABEL: array_or_not_dup_v8i16:
+; CHECK-SD:       // %bb.0: // %entry
+; CHECK-SD-NEXT:    dup v0.8h, w1
+; CHECK-SD-NEXT:    mov x8, xzr
+; CHECK-SD-NEXT:  .LBB224_1: // %vector.body
+; CHECK-SD-NEXT:    // =>This Inner Loop Header: Depth=1
+; CHECK-SD-NEXT:    ldr q1, [x0, x8]
+; CHECK-SD-NEXT:    orn v1.16b, v1.16b, v0.16b
+; CHECK-SD-NEXT:    str q1, [x0, x8]
+; CHECK-SD-NEXT:    add x8, x8, #16
+; CHECK-SD-NEXT:    cmp x8, #512
+; CHECK-SD-NEXT:    b.ne .LBB224_1
+; CHECK-SD-NEXT:  // %bb.2: // %for.cond.cleanup
+; CHECK-SD-NEXT:    ret
+;
+; CHECK-GI-LABEL: array_or_not_dup_v8i16:
+; CHECK-GI:       // %bb.0: // %entry
+; CHECK-GI-NEXT:    mvn w8, w1
+; CHECK-GI-NEXT:    dup v0.8h, w8
+; CHECK-GI-NEXT:    mov x8, xzr
+; CHECK-GI-NEXT:  .LBB224_1: // %vector.body
+; CHECK-GI-NEXT:    // =>This Inner Loop Header: Depth=1
+; CHECK-GI-NEXT:    ldr q1, [x0, x8]
+; CHECK-GI-NEXT:    orr v1.16b, v1.16b, v0.16b
+; CHECK-GI-NEXT:    str q1, [x0, x8]
+; CHECK-GI-NEXT:    add x8, x8, #16
+; CHECK-GI-NEXT:    cmp x8, #512
+; CHECK-GI-NEXT:    b.ne .LBB224_1
+; CHECK-GI-NEXT:  // %bb.2: // %for.cond.cleanup
+; CHECK-GI-NEXT:    ret
 entry:
   %not = xor i16 %m, -1
   %broadcast.splatinsert = insertelement <8 x i16> poison, i16 %not, i64 0
@@ -3982,21 +3952,36 @@ for.cond.cleanup:
 }
 
 define void @array_or_not_dup_v4i32(ptr %a, i32 %m) {
-; CHECK-LABEL: array_or_not_dup_v4i32:
-; CHECK:       // %bb.0: // %entry
-; CHECK-NEXT:    mvn w8, w1
-; CHECK-NEXT:    dup v0.4s, w8
-; CHECK-NEXT:    mov x8, xzr
-; CHECK-NEXT:  .LBB225_1: // %vector.body
-; CHECK-NEXT:    // =>This Inner Loop Header: Depth=1
-; CHECK-NEXT:    ldr q1, [x0, x8]
-; CHECK-NEXT:    orr v1.16b, v1.16b, v0.16b
-; CHECK-NEXT:    str q1, [x0, x8]
-; CHECK-NEXT:    add x8, x8, #16
-; CHECK-NEXT:    cmp x8, #1024
-; CHECK-NEXT:    b.ne .LBB225_1
-; CHECK-NEXT:  // %bb.2: // %for.cond.cleanup
-; CHECK-NEXT:    ret
+; CHECK-SD-LABEL: array_or_not_dup_v4i32:
+; CHECK-SD:       // %bb.0: // %entry
+; CHECK-SD-NEXT:    dup v0.4s, w1
+; CHECK-SD-NEXT:    mov x8, xzr
+; CHECK-SD-NEXT:  .LBB225_1: // %vector.body
+; CHECK-SD-NEXT:    // =>This Inner Loop Header: Depth=1
+; CHECK-SD-NEXT:    ldr q1, [x0, x8]
+; CHECK-SD-NEXT:    orn v1.16b, v1.16b, v0.16b
+; CHECK-SD-NEXT:    str q1, [x0, x8]
+; CHECK-SD-NEXT:    add x8, x8, #16
+; CHECK-SD-NEXT:    cmp x8, #1024
+; CHECK-SD-NEXT:    b.ne .LBB225_1
+; CHECK-SD-NEXT:  // %bb.2: // %for.cond.cleanup
+; CHECK-SD-NEXT:    ret
+;
+; CHECK-GI-LABEL: array_or_not_dup_v4i32:
+; CHECK-GI:       // %bb.0: // %entry
+; CHECK-GI-NEXT:    mvn w8, w1
+; CHECK-GI-NEXT:    dup v0.4s, w8
+; CHECK-GI-NEXT:    mov x8, xzr
+; CHECK-GI-NEXT:  .LBB225_1: // %vector.body
+; CHECK-GI-NEXT:    // =>This Inner Loop Header: Depth=1
+; CHECK-GI-NEXT:    ldr q1, [x0, x8]
+; CHECK-GI-NEXT:    orr v1.16b, v1.16b, v0.16b
+; CHECK-GI-NEXT:    str q1, [x0, x8]
+; CHECK-GI-NEXT:    add x8, x8, #16
+; CHECK-GI-NEXT:    cmp x8, #1024
+; CHECK-GI-NEXT:    b.ne .LBB225_1
+; CHECK-GI-NEXT:  // %bb.2: // %for.cond.cleanup
+; CHECK-GI-NEXT:    ret
 entry:
   %not = xor i32 %m, -1
   %broadcast.splatinsert = insertelement <4 x i32> poison, i32 %not, i64 0
@@ -4018,21 +4003,36 @@ for.cond.cleanup:
 }
 
 define void @array_or_not_dup_v2i64(ptr %a, i64 %m) {
-; CHECK-LABEL: array_or_not_dup_v2i64:
-; CHECK:       // %bb.0: // %entry
-; CHECK-NEXT:    mvn x8, x1
-; CHECK-NEXT:    dup v0.2d, x8
-; CHECK-NEXT:    mov x8, xzr
-; CHECK-NEXT:  .LBB226_1: // %vector.body
-; CHECK-NEXT:    // =>This Inner Loop Header: Depth=1
-; CHECK-NEXT:    ldr q1, [x0, x8]
-; CHECK-NEXT:    orr v1.16b, v1.16b, v0.16b
-; CHECK-NEXT:    str q1, [x0, x8]
-; CHECK-NEXT:    add x8, x8, #16
-; CHECK-NEXT:    cmp x8, #2048
-; CHECK-NEXT:    b.ne .LBB226_1
-; CHECK-NEXT:  // %bb.2: // %for.cond.cleanup
-; CHECK-NEXT:    ret
+; CHECK-SD-LABEL: array_or_not_dup_v2i64:
+; CHECK-SD:       // %bb.0: // %entry
+; CHECK-SD-NEXT:    dup v0.2d, x1
+; CHECK-SD-NEXT:    mov x8, xzr
+; CHECK-SD-NEXT:  .LBB226_1: // %vector.body
+; CHECK-SD-NEXT:    // =>This Inner Loop Header: Depth=1
+; CHECK-SD-NEXT:    ldr q1, [x0, x8]
+; CHECK-SD-NEXT:    orn v1.16b, v1.16b, v0.16b
+; CHECK-SD-NEXT:    str q1, [x0, x8]
+; CHECK-SD-NEXT:    add x8, x8, #16
+; CHECK-SD-NEXT:    cmp x8, #2048
+; CHECK-SD-NEXT:    b.ne .LBB226_1
+; CHECK-SD-NEXT:  // %bb.2: // %for.cond.cleanup
+; CHECK-SD-NEXT:    ret
+;
+; CHECK-GI-LABEL: array_or_not_dup_v2i64:
+; CHECK-GI:       // %bb.0: // %entry
+; CHECK-GI-NEXT:    mvn x8, x1
+; CHECK-GI-NEXT:    dup v0.2d, x8
+; CHECK-GI-NEXT:    mov x8, xzr
+; CHECK-GI-NEXT:  .LBB226_1: // %vector.body
+; CHECK-GI-NEXT:    // =>This Inner Loop Header: Depth=1
+; CHECK-GI-NEXT:    ldr q1, [x0, x8]
+; CHECK-GI-NEXT:    orr v1.16b, v1.16b, v0.16b
+; CHECK-GI-NEXT:    str q1, [x0, x8]
+; CHECK-GI-NEXT:    add x8, x8, #16
+; CHECK-GI-NEXT:    cmp x8, #2048
+; CHECK-GI-NEXT:    b.ne .LBB226_1
+; CHECK-GI-NEXT:  // %bb.2: // %for.cond.cleanup
+; CHECK-GI-NEXT:    ret
 entry:
   %not = xor i64 %m, -1
   %broadcast.splatinsert = insertelement <2 x i64> poison, i64 %not, i64 0

>From dee61fa844e004a701c030323fa4d20e23aa1063 Mon Sep 17 00:00:00 2001
From: Piotr Fusik <p.fusik at samsung.com>
Date: Thu, 15 Jan 2026 16:39:37 +0100
Subject: [PATCH 3/4] [AArch64][test] Prefer folding a shift to NOT

---
 .../CodeGen/AArch64/logical-op-with-not.ll    | 34 +++++++++++++++++++
 1 file changed, 34 insertions(+)

diff --git a/llvm/test/CodeGen/AArch64/logical-op-with-not.ll b/llvm/test/CodeGen/AArch64/logical-op-with-not.ll
index 4b35f92e6c660..375eab5ae78bb 100644
--- a/llvm/test/CodeGen/AArch64/logical-op-with-not.ll
+++ b/llvm/test/CodeGen/AArch64/logical-op-with-not.ll
@@ -704,3 +704,37 @@ for.body:
   %exitcond.not = icmp eq i64 %indvars.iv.next, 16
   br i1 %exitcond.not, label %for.cond.cleanup, label %for.body
 }
+
+define void @array_and_lsl2_not_i32(ptr %a, i32 %m) {
+; CHECK-LABEL: array_and_lsl2_not_i32:
+; CHECK:       // %bb.0: // %entry
+; CHECK-NEXT:    mov x8, xzr
+; CHECK-NEXT:  .LBB38_1: // %for.body
+; CHECK-NEXT:    // =>This Inner Loop Header: Depth=1
+; CHECK-NEXT:    ldr w9, [x0, x8]
+; CHECK-NEXT:    lsl w9, w9, #2
+; CHECK-NEXT:    bic w9, w9, w1
+; CHECK-NEXT:    str w9, [x0, x8]
+; CHECK-NEXT:    add x8, x8, #4
+; CHECK-NEXT:    cmp x8, #1024
+; CHECK-NEXT:    b.ne .LBB38_1
+; CHECK-NEXT:  // %bb.2: // %for.cond.cleanup
+; CHECK-NEXT:    ret
+entry:
+  %not = xor i32 %m, -1
+  br label %for.body
+
+for.cond.cleanup:
+  ret void
+
+for.body:
+  %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ]
+  %arrayidx = getelementptr inbounds nuw i32, ptr %a, i64 %indvars.iv
+  %0 = load i32, ptr %arrayidx, align 4
+  %shl = shl i32 %0, 2
+  %and = and i32 %shl, %not
+  store i32 %and, ptr %arrayidx, align 4
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  %exitcond.not = icmp eq i64 %indvars.iv.next, 256
+  br i1 %exitcond.not, label %for.cond.cleanup, label %for.body
+}

>From 9d746a716d72f91afd9f17a6a48559e3dfae4a9a Mon Sep 17 00:00:00 2001
From: Piotr Fusik <p.fusik at samsung.com>
Date: Thu, 15 Jan 2026 16:57:56 +0100
Subject: [PATCH 4/4] [AArch64] Prefer folding a shift to NOT

---
 llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp | 5 +++++
 llvm/test/CodeGen/AArch64/logical-op-with-not.ll       | 8 ++++----
 2 files changed, 9 insertions(+), 4 deletions(-)

diff --git a/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp b/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp
index 529846f5edbd8..8148cac8fe107 100644
--- a/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp
+++ b/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp
@@ -6824,6 +6824,11 @@ bool AArch64TTIImpl::isProfitableToSinkOperands(
     [[fallthrough]];
   case Instruction::And:
   case Instruction::Or:
+    // Shift can be fold into scalar AND/ORR/EOR,
+    // but not the non-negated operand of BIC/ORN/EON.
+    if (!(I->getType()->isVectorTy() && ST->hasNEON()) &&
+        match(I, m_c_BinOp(m_Shift(m_Value(), m_ConstantInt()), m_Value())))
+      break;
     for (auto &Op : I->operands()) {
       // (and/or/xor X, (not Y)) -> (bic/orn/eon X, Y)
       if (match(Op.get(), m_Not(m_Value()))) {
diff --git a/llvm/test/CodeGen/AArch64/logical-op-with-not.ll b/llvm/test/CodeGen/AArch64/logical-op-with-not.ll
index 375eab5ae78bb..2f5610a18aa9c 100644
--- a/llvm/test/CodeGen/AArch64/logical-op-with-not.ll
+++ b/llvm/test/CodeGen/AArch64/logical-op-with-not.ll
@@ -709,12 +709,12 @@ define void @array_and_lsl2_not_i32(ptr %a, i32 %m) {
 ; CHECK-LABEL: array_and_lsl2_not_i32:
 ; CHECK:       // %bb.0: // %entry
 ; CHECK-NEXT:    mov x8, xzr
+; CHECK-NEXT:    mvn w9, w1
 ; CHECK-NEXT:  .LBB38_1: // %for.body
 ; CHECK-NEXT:    // =>This Inner Loop Header: Depth=1
-; CHECK-NEXT:    ldr w9, [x0, x8]
-; CHECK-NEXT:    lsl w9, w9, #2
-; CHECK-NEXT:    bic w9, w9, w1
-; CHECK-NEXT:    str w9, [x0, x8]
+; CHECK-NEXT:    ldr w10, [x0, x8]
+; CHECK-NEXT:    and w10, w9, w10, lsl #2
+; CHECK-NEXT:    str w10, [x0, x8]
 ; CHECK-NEXT:    add x8, x8, #4
 ; CHECK-NEXT:    cmp x8, #1024
 ; CHECK-NEXT:    b.ne .LBB38_1



More information about the llvm-commits mailing list