[llvm-branch-commits] [llvm] [AArch64][TTI] Cost NEON Nots absorbed by And/Or users as free (PR #232788)

Valeriy Savchenko via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Mon Oct 19 04:59:49 PDT 2026


https://github.com/SavchenkoValeriy updated https://github.com/llvm/llvm-project/pull/232788

>From b1f7f438adc39626191f75d5243e3c1820a2f9bb Mon Sep 17 00:00:00 2001
From: Valeriy Savchenko <vsavchenko at apple.com>
Date: Fri, 16 Oct 2026 15:20:41 +0100
Subject: [PATCH 1/2] [AArch64][TTI] Add pre-commit tests (NFC)

---
 llvm/test/Analysis/CostModel/AArch64/bsl.ll | 87 ++++++++++++++++++++-
 1 file changed, 85 insertions(+), 2 deletions(-)

diff --git a/llvm/test/Analysis/CostModel/AArch64/bsl.ll b/llvm/test/Analysis/CostModel/AArch64/bsl.ll
index 80a03e7307ac2..d973d959c5b89 100644
--- a/llvm/test/Analysis/CostModel/AArch64/bsl.ll
+++ b/llvm/test/Analysis/CostModel/AArch64/bsl.ll
@@ -81,6 +81,89 @@ define <8 x i8> @bsl_not_multiuse(<8 x i8> %m, <8 x i8> %a, <8 x i8> %b, ptr %p)
   ret <8 x i8> %r
 }
 
+define <8 x i8> @bic(<8 x i8> %a, <8 x i8> %m) {
+; COST-LABEL: 'bic'
+; COST-NEXT:  Cost Model: Found costs of 1 for: %n = xor <8 x i8> %m, splat (i8 -1)
+; COST-NEXT:  Cost Model: Found costs of 1 for: %r = and <8 x i8> %a, %n
+; COST-NEXT:  Cost Model: Found costs of RThru:0 CodeSize:1 Lat:1 SizeLat:1 for: ret <8 x i8> %r
+;
+; CODE-LABEL: bic:
+; CODE:       // %bb.0:
+; CODE-NEXT:    bic v0.8b, v0.8b, v1.8b
+; CODE-NEXT:    ret
+  %n = xor <8 x i8> %m, splat (i8 -1)
+  %r = and <8 x i8> %a, %n
+  ret <8 x i8> %r
+}
+
+define <8 x i8> @orn(<8 x i8> %a, <8 x i8> %m) {
+; COST-LABEL: 'orn'
+; COST-NEXT:  Cost Model: Found costs of 1 for: %n = xor <8 x i8> %m, splat (i8 -1)
+; COST-NEXT:  Cost Model: Found costs of 1 for: %r = or <8 x i8> %a, %n
+; COST-NEXT:  Cost Model: Found costs of RThru:0 CodeSize:1 Lat:1 SizeLat:1 for: ret <8 x i8> %r
+;
+; CODE-LABEL: orn:
+; CODE:       // %bb.0:
+; CODE-NEXT:    orn v0.8b, v0.8b, v1.8b
+; CODE-NEXT:    ret
+  %n = xor <8 x i8> %m, splat (i8 -1)
+  %r = or <8 x i8> %a, %n
+  ret <8 x i8> %r
+}
+
+define <8 x i8> @neg_not_xor(<8 x i8> %a, <8 x i8> %m) {
+; COST-LABEL: 'neg_not_xor'
+; COST-NEXT:  Cost Model: Found costs of 1 for: %n = xor <8 x i8> %m, splat (i8 -1)
+; COST-NEXT:  Cost Model: Found costs of 1 for: %r = xor <8 x i8> %a, %n
+; COST-NEXT:  Cost Model: Found costs of RThru:0 CodeSize:1 Lat:1 SizeLat:1 for: ret <8 x i8> %r
+;
+; CODE-LABEL: neg_not_xor:
+; CODE:       // %bb.0:
+; CODE-NEXT:    eor v0.8b, v1.8b, v0.8b
+; CODE-NEXT:    mvn v0.8b, v0.8b
+; CODE-NEXT:    ret
+  %n = xor <8 x i8> %m, splat (i8 -1)
+  %r = xor <8 x i8> %a, %n
+  ret <8 x i8> %r
+}
+
+define <8 x i8> @neg_not_two_nots(<8 x i8> %a, <8 x i8> %b) {
+; COST-LABEL: 'neg_not_two_nots'
+; COST-NEXT:  Cost Model: Found costs of 1 for: %na = xor <8 x i8> %a, splat (i8 -1)
+; COST-NEXT:  Cost Model: Found costs of 1 for: %nb = xor <8 x i8> %b, splat (i8 -1)
+; COST-NEXT:  Cost Model: Found costs of 1 for: %r = and <8 x i8> %na, %nb
+; COST-NEXT:  Cost Model: Found costs of RThru:0 CodeSize:1 Lat:1 SizeLat:1 for: ret <8 x i8> %r
+;
+; CODE-LABEL: neg_not_two_nots:
+; CODE:       // %bb.0:
+; CODE-NEXT:    mvn v0.8b, v0.8b
+; CODE-NEXT:    bic v0.8b, v0.8b, v1.8b
+; CODE-NEXT:    ret
+  %na = xor <8 x i8> %a, splat (i8 -1)
+  %nb = xor <8 x i8> %b, splat (i8 -1)
+  %r = and <8 x i8> %na, %nb
+  ret <8 x i8> %r
+}
+
+define <8 x i8> @neg_not_bic_and_add(<8 x i8> %a, <8 x i8> %m) {
+; COST-LABEL: 'neg_not_bic_and_add'
+; COST-NEXT:  Cost Model: Found costs of 1 for: %n = xor <8 x i8> %m, splat (i8 -1)
+; COST-NEXT:  Cost Model: Found costs of 1 for: %r = and <8 x i8> %a, %n
+; COST-NEXT:  Cost Model: Found costs of 1 for: %s = add <8 x i8> %r, %n
+; COST-NEXT:  Cost Model: Found costs of RThru:0 CodeSize:1 Lat:1 SizeLat:1 for: ret <8 x i8> %s
+;
+; CODE-LABEL: neg_not_bic_and_add:
+; CODE:       // %bb.0:
+; CODE-NEXT:    mvn v2.8b, v1.8b
+; CODE-NEXT:    bic v0.8b, v0.8b, v1.8b
+; CODE-NEXT:    add v0.8b, v0.8b, v2.8b
+; CODE-NEXT:    ret
+  %n = xor <8 x i8> %m, splat (i8 -1)
+  %r = and <8 x i8> %a, %n
+  %s = add <8 x i8> %r, %n
+  ret <8 x i8> %s
+}
+
 ; TODO: BIT is still formed, so %y and the Not should be free.
 define <8 x i8> @neg_bsl_and_multiuse(<8 x i8> %m, <8 x i8> %a, <8 x i8> %b, ptr %p) {
 ; COST-LABEL: 'neg_bsl_and_multiuse'
@@ -119,13 +202,13 @@ define <8 x i8> @neg_bsl_other_block(<8 x i8> %m, <8 x i8> %a, <8 x i8> %b, i1 %
 ;
 ; CODE-LABEL: neg_bsl_other_block:
 ; CODE:       // %bb.0: // %entry
-; CODE-NEXT:    tbz w0, #0, .LBB4_2
+; CODE-NEXT:    tbz w0, #0, .LBB9_2
 ; CODE-NEXT:  // %bb.1: // %t
 ; CODE-NEXT:    and v1.8b, v0.8b, v1.8b
 ; CODE-NEXT:    bic v0.8b, v2.8b, v0.8b
 ; CODE-NEXT:    orr v1.8b, v1.8b, v0.8b
 ; CODE-NEXT:    str d1, [x1]
-; CODE-NEXT:  .LBB4_2: // %common.ret
+; CODE-NEXT:  .LBB9_2: // %common.ret
 ; CODE-NEXT:    fmov d0, d1
 ; CODE-NEXT:    ret
 entry:

>From 6a32a2897dfc00fe56f2b8e0883fa512d3d6c307 Mon Sep 17 00:00:00 2001
From: Valeriy Savchenko <vsavchenko at apple.com>
Date: Fri, 16 Oct 2026 15:31:54 +0100
Subject: [PATCH 2/2] [AArch64][TTI] Cost NEON Nots absorbed by And/Or users as
 free

---
 .../AArch64/AArch64TargetTransformInfo.cpp       | 12 ++++++++++++
 llvm/test/Analysis/CostModel/AArch64/bsl.ll      | 16 +++++++---------
 2 files changed, 19 insertions(+), 9 deletions(-)

diff --git a/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp b/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp
index 561cca222b26f..fe3a541d6530d 100644
--- a/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp
+++ b/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp
@@ -5131,6 +5131,18 @@ InstructionCost AArch64TTIImpl::getArithmeticInstrCost(
     if (Opcode == Instruction::And &&
         matchBSL(CtxI->user_back(), MainAnd, OtherAnd, A, B))
       return 0;
+
+    // A Not is folded into the BIC, ORN or BSL of each And/Or using it, unless
+    // that And/Or negates both of its operands.
+    if (match(CtxI, m_Not(m_Value())) &&
+        all_of(CtxI->users(), [&](const User *U) {
+          const auto *UI = cast<Instruction>(U);
+          return is_contained({Instruction::And, Instruction::Or},
+                              UI->getOpcode()) &&
+                 UI->getParent() == CtxI->getParent() &&
+                 !match(UI, m_BinOp(m_Not(m_Value()), m_Not(m_Value())));
+        }))
+      return 0;
   }
 
   // Legalize the type.
diff --git a/llvm/test/Analysis/CostModel/AArch64/bsl.ll b/llvm/test/Analysis/CostModel/AArch64/bsl.ll
index d973d959c5b89..39eada0472a88 100644
--- a/llvm/test/Analysis/CostModel/AArch64/bsl.ll
+++ b/llvm/test/Analysis/CostModel/AArch64/bsl.ll
@@ -4,10 +4,9 @@
 
 target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128"
 
-; TODO: The Not is folded into BSL and should be free.
 define <8 x i8> @bsl(<8 x i8> %m, <8 x i8> %a, <8 x i8> %b) {
 ; COST-LABEL: 'bsl'
-; COST-NEXT:  Cost Model: Found costs of 1 for: %n = xor <8 x i8> %m, splat (i8 -1)
+; COST-NEXT:  Cost Model: Found costs of 0 for: %n = xor <8 x i8> %m, splat (i8 -1)
 ; COST-NEXT:  Cost Model: Found costs of 0 for: %x = and <8 x i8> %m, %a
 ; COST-NEXT:  Cost Model: Found costs of 0 for: %y = and <8 x i8> %n, %b
 ; COST-NEXT:  Cost Model: Found costs of 1 for: %r = or <8 x i8> %x, %y
@@ -24,10 +23,9 @@ define <8 x i8> @bsl(<8 x i8> %m, <8 x i8> %a, <8 x i8> %b) {
   ret <8 x i8> %r
 }
 
-; TODO: The Not should be free here as well
 define void @bsl_shared_mask(<16 x i8> %m, <16 x i8> %a, <16 x i8> %b, <16 x i8> %c, <16 x i8> %d, ptr %p, ptr %q) {
 ; COST-LABEL: 'bsl_shared_mask'
-; COST-NEXT:  Cost Model: Found costs of 1 for: %n = xor <16 x i8> %m, splat (i8 -1)
+; COST-NEXT:  Cost Model: Found costs of 0 for: %n = xor <16 x i8> %m, splat (i8 -1)
 ; COST-NEXT:  Cost Model: Found costs of 0 for: %x0 = and <16 x i8> %m, %a
 ; COST-NEXT:  Cost Model: Found costs of 0 for: %y0 = and <16 x i8> %n, %b
 ; COST-NEXT:  Cost Model: Found costs of 1 for: %r0 = or <16 x i8> %x0, %y0
@@ -83,7 +81,7 @@ define <8 x i8> @bsl_not_multiuse(<8 x i8> %m, <8 x i8> %a, <8 x i8> %b, ptr %p)
 
 define <8 x i8> @bic(<8 x i8> %a, <8 x i8> %m) {
 ; COST-LABEL: 'bic'
-; COST-NEXT:  Cost Model: Found costs of 1 for: %n = xor <8 x i8> %m, splat (i8 -1)
+; COST-NEXT:  Cost Model: Found costs of 0 for: %n = xor <8 x i8> %m, splat (i8 -1)
 ; COST-NEXT:  Cost Model: Found costs of 1 for: %r = and <8 x i8> %a, %n
 ; COST-NEXT:  Cost Model: Found costs of RThru:0 CodeSize:1 Lat:1 SizeLat:1 for: ret <8 x i8> %r
 ;
@@ -98,7 +96,7 @@ define <8 x i8> @bic(<8 x i8> %a, <8 x i8> %m) {
 
 define <8 x i8> @orn(<8 x i8> %a, <8 x i8> %m) {
 ; COST-LABEL: 'orn'
-; COST-NEXT:  Cost Model: Found costs of 1 for: %n = xor <8 x i8> %m, splat (i8 -1)
+; COST-NEXT:  Cost Model: Found costs of 0 for: %n = xor <8 x i8> %m, splat (i8 -1)
 ; COST-NEXT:  Cost Model: Found costs of 1 for: %r = or <8 x i8> %a, %n
 ; COST-NEXT:  Cost Model: Found costs of RThru:0 CodeSize:1 Lat:1 SizeLat:1 for: ret <8 x i8> %r
 ;
@@ -164,10 +162,10 @@ define <8 x i8> @neg_not_bic_and_add(<8 x i8> %a, <8 x i8> %m) {
   ret <8 x i8> %s
 }
 
-; TODO: BIT is still formed, so %y and the Not should be free.
+; TODO: BIT is still formed, so %y should be free.
 define <8 x i8> @neg_bsl_and_multiuse(<8 x i8> %m, <8 x i8> %a, <8 x i8> %b, ptr %p) {
 ; COST-LABEL: 'neg_bsl_and_multiuse'
-; COST-NEXT:  Cost Model: Found costs of 1 for: %n = xor <8 x i8> %m, splat (i8 -1)
+; COST-NEXT:  Cost Model: Found costs of 0 for: %n = xor <8 x i8> %m, splat (i8 -1)
 ; COST-NEXT:  Cost Model: Found costs of 1 for: %x = and <8 x i8> %m, %a
 ; COST-NEXT:  Cost Model: Found costs of 1 for: %y = and <8 x i8> %n, %b
 ; COST-NEXT:  Cost Model: Found costs of 1 for: %r = or <8 x i8> %x, %y
@@ -191,7 +189,7 @@ define <8 x i8> @neg_bsl_and_multiuse(<8 x i8> %m, <8 x i8> %a, <8 x i8> %b, ptr
 
 define <8 x i8> @neg_bsl_other_block(<8 x i8> %m, <8 x i8> %a, <8 x i8> %b, i1 %f, ptr %p) {
 ; COST-LABEL: 'neg_bsl_other_block'
-; COST-NEXT:  Cost Model: Found costs of 1 for: %n = xor <8 x i8> %m, splat (i8 -1)
+; COST-NEXT:  Cost Model: Found costs of 0 for: %n = xor <8 x i8> %m, splat (i8 -1)
 ; COST-NEXT:  Cost Model: Found costs of 1 for: %x = and <8 x i8> %m, %a
 ; COST-NEXT:  Cost Model: Found costs of 1 for: %y = and <8 x i8> %n, %b
 ; COST-NEXT:  Cost Model: Found costs of RThru:0 CodeSize:1 Lat:1 SizeLat:1 for: br i1 %f, label %t, label %e



More information about the llvm-branch-commits mailing list