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

via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Fri Oct 16 07:59:46 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-backend-aarch64

Author: Valeriy Savchenko (SavchenkoValeriy)

<details>
<summary>Changes</summary>

Cost a NEON Not as free when every user is an And/Or in the same block, 
since the Not folds into its BIC, ORN or BSL. If a user negates both of
its operands, only one Not can fold, so it still counts.

---

<sub>Stack created with <a href="https://github.com/github/gh-stack">GitHub Stacks CLI</a> • <a href="https://gh.io/stacks-feedback">Give Feedback 💬</a></sub>

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


2 Files Affected:

- (modified) llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp (+12) 
- (modified) llvm/test/Analysis/CostModel/AArch64/bsl.ll (+90-9) 


``````````diff
diff --git a/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp b/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp
index e4a883d3a960e..5d3be19fe23d0 100644
--- a/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp
+++ b/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp
@@ -5119,6 +5119,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 80a03e7307ac2..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
@@ -81,10 +79,93 @@ 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
 }
 
-; TODO: BIT is still formed, so %y and the Not should be free.
+define <8 x i8> @bic(<8 x i8> %a, <8 x i8> %m) {
+; COST-LABEL: 'bic'
+; 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
+;
+; 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 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
+;
+; 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 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
@@ -108,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
@@ -119,13 +200,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:

``````````

</details>


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


More information about the llvm-branch-commits mailing list