[llvm] [GlobalISel] Add G_UAVGFLOOR/G_UAVGCEIL/G_SAVGFLOOR/G_SAVGCEIL to computeKnownBits (PR #209171)

via llvm-commits llvm-commits at lists.llvm.org
Mon Jul 13 06:02:47 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-llvm-globalisel

@llvm/pr-subscribers-backend-aarch64

Author: Joel Walker  (Joel-Wwalker)

<details>
<summary>Changes</summary>

Add known-bits handling for the averaging (halving add) opcodes G_UAVGFLOOR,
G_UAVGCEIL, G_SAVGFLOOR and G_SAVGCEIL in GISelValueTracking, using the
existing `KnownBits::avg{Floor,Ceil}{S,U}` helpers. This matches
SelectionDAG's handling of the corresponding ISD::AVGFLOOR*/AVGCEIL* nodes.

This lets GlobalISel drop the redundant masking around hadd/rhadd of
zero-extended operands on AArch64 (see aarch64-known-bits-hadd.ll, where the
GlobalISel output now matches SelectionDAG). The sign-extended cases are
unaffected, since the masking is not redundant there.

Part of #<!-- -->150515.

---
Assisted by Claude (Anthropic).


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


3 Files Affected:

- (modified) llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp (+32) 
- (added) llvm/test/CodeGen/AArch64/GlobalISel/knownbits-avg.mir (+131) 
- (modified) llvm/test/CodeGen/AArch64/aarch64-known-bits-hadd.ll (+6-23) 


``````````diff
diff --git a/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp b/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp
index 5602038c828dd..9eea63420d551 100644
--- a/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp
@@ -398,6 +398,38 @@ void GISelValueTracking::computeKnownBitsImpl(Register R, KnownBits &Known,
     Known = KnownBits::mulhs(Known, Known2);
     break;
   }
+  case TargetOpcode::G_UAVGFLOOR: {
+    computeKnownBitsImpl(MI.getOperand(1).getReg(), Known, DemandedElts,
+                         Depth + 1);
+    computeKnownBitsImpl(MI.getOperand(2).getReg(), Known2, DemandedElts,
+                         Depth + 1);
+    Known = KnownBits::avgFloorU(Known, Known2);
+    break;
+  }
+  case TargetOpcode::G_UAVGCEIL: {
+    computeKnownBitsImpl(MI.getOperand(1).getReg(), Known, DemandedElts,
+                         Depth + 1);
+    computeKnownBitsImpl(MI.getOperand(2).getReg(), Known2, DemandedElts,
+                         Depth + 1);
+    Known = KnownBits::avgCeilU(Known, Known2);
+    break;
+  }
+  case TargetOpcode::G_SAVGFLOOR: {
+    computeKnownBitsImpl(MI.getOperand(1).getReg(), Known, DemandedElts,
+                         Depth + 1);
+    computeKnownBitsImpl(MI.getOperand(2).getReg(), Known2, DemandedElts,
+                         Depth + 1);
+    Known = KnownBits::avgFloorS(Known, Known2);
+    break;
+  }
+  case TargetOpcode::G_SAVGCEIL: {
+    computeKnownBitsImpl(MI.getOperand(1).getReg(), Known, DemandedElts,
+                         Depth + 1);
+    computeKnownBitsImpl(MI.getOperand(2).getReg(), Known2, DemandedElts,
+                         Depth + 1);
+    Known = KnownBits::avgCeilS(Known, Known2);
+    break;
+  }
   case TargetOpcode::G_ABDU: {
     computeKnownBitsImpl(MI.getOperand(2).getReg(), Known, DemandedElts,
                          Depth + 1);
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/knownbits-avg.mir b/llvm/test/CodeGen/AArch64/GlobalISel/knownbits-avg.mir
new file mode 100644
index 0000000000000..9e1d485a035e0
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/knownbits-avg.mir
@@ -0,0 +1,131 @@
+# NOTE: Assertions have been autogenerated by utils/update_givaluetracking_test_checks.py UTC_ARGS: --version 6
+# RUN: llc -mtriple=aarch64 -passes="print<gisel-value-tracking>" -filetype=null %s 2>&1 | FileCheck %s
+
+---
+name: Cst_UAvgFloor
+body: |
+  bb.0:
+  ; CHECK-LABEL: name: @Cst_UAvgFloor
+  ; CHECK-NEXT: %0:_ KnownBits:00001011 SignBits:4
+  ; CHECK-NEXT: %1:_ KnownBits:00000100 SignBits:5
+  ; CHECK-NEXT: %2:_ KnownBits:00000111 SignBits:5
+    %0:_(i8) = G_CONSTANT i8 11
+    %1:_(i8) = G_CONSTANT i8 4
+    %2:_(i8) = G_UAVGFLOOR %0, %1
+...
+---
+name: Cst_UAvgCeil
+body: |
+  bb.0:
+  ; CHECK-LABEL: name: @Cst_UAvgCeil
+  ; CHECK-NEXT: %0:_ KnownBits:00001011 SignBits:4
+  ; CHECK-NEXT: %1:_ KnownBits:00000100 SignBits:5
+  ; CHECK-NEXT: %2:_ KnownBits:00001000 SignBits:4
+    %0:_(i8) = G_CONSTANT i8 11
+    %1:_(i8) = G_CONSTANT i8 4
+    %2:_(i8) = G_UAVGCEIL %0, %1
+...
+---
+name: CstNoOverflow_UAvgFloor
+body: |
+  bb.0:
+  ; CHECK-LABEL: name: @CstNoOverflow_UAvgFloor
+  ; CHECK-NEXT: %0:_ KnownBits:11001000 SignBits:2
+  ; CHECK-NEXT: %1:_ KnownBits:01100100 SignBits:1
+  ; CHECK-NEXT: %2:_ KnownBits:10010110 SignBits:1
+    %0:_(i8) = G_CONSTANT i8 200
+    %1:_(i8) = G_CONSTANT i8 100
+    %2:_(i8) = G_UAVGFLOOR %0, %1
+...
+---
+name: CstNoOverflow_UAvgCeil
+body: |
+  bb.0:
+  ; CHECK-LABEL: name: @CstNoOverflow_UAvgCeil
+  ; CHECK-NEXT: %0:_ KnownBits:11111111 SignBits:8
+  ; CHECK-NEXT: %1:_ KnownBits:11111111 SignBits:8
+  ; CHECK-NEXT: %2:_ KnownBits:11111111 SignBits:8
+    %0:_(i8) = G_CONSTANT i8 255
+    %1:_(i8) = G_CONSTANT i8 255
+    %2:_(i8) = G_UAVGCEIL %0, %1
+...
+---
+name: Cst_SAvgFloor
+body: |
+  bb.0:
+  ; CHECK-LABEL: name: @Cst_SAvgFloor
+  ; CHECK-NEXT: %0:_ KnownBits:11110110 SignBits:4
+  ; CHECK-NEXT: %1:_ KnownBits:00000100 SignBits:5
+  ; CHECK-NEXT: %2:_ KnownBits:11111101 SignBits:6
+    %0:_(i8) = G_CONSTANT i8 -10
+    %1:_(i8) = G_CONSTANT i8 4
+    %2:_(i8) = G_SAVGFLOOR %0, %1
+...
+---
+name: CstNoOverflow_SAvgFloor
+body: |
+  bb.0:
+  ; CHECK-LABEL: name: @CstNoOverflow_SAvgFloor
+  ; CHECK-NEXT: %0:_ KnownBits:10011100 SignBits:1
+  ; CHECK-NEXT: %1:_ KnownBits:10011100 SignBits:1
+  ; CHECK-NEXT: %2:_ KnownBits:10011100 SignBits:1
+    %0:_(i8) = G_CONSTANT i8 -100
+    %1:_(i8) = G_CONSTANT i8 -100
+    %2:_(i8) = G_SAVGFLOOR %0, %1
+...
+---
+name: CstNoOverflow_SAvgCeil
+body: |
+  bb.0:
+  ; CHECK-LABEL: name: @CstNoOverflow_SAvgCeil
+  ; CHECK-NEXT: %0:_ KnownBits:01111111 SignBits:1
+  ; CHECK-NEXT: %1:_ KnownBits:01111111 SignBits:1
+  ; CHECK-NEXT: %2:_ KnownBits:01111111 SignBits:1
+    %0:_(i8) = G_CONSTANT i8 127
+    %1:_(i8) = G_CONSTANT i8 127
+    %2:_(i8) = G_SAVGCEIL %0, %1
+...
+---
+name: PartialKnown_UAvgFloor
+body: |
+  bb.0:
+  ; CHECK-LABEL: name: @PartialKnown_UAvgFloor
+  ; CHECK-NEXT: %0:_ KnownBits:???????? SignBits:1
+  ; CHECK-NEXT: %1:_ KnownBits:00001111 SignBits:4
+  ; CHECK-NEXT: %2:_ KnownBits:0000???? SignBits:4
+  ; CHECK-NEXT: %3:_ KnownBits:00000100 SignBits:5
+  ; CHECK-NEXT: %4:_ KnownBits:0000???? SignBits:4
+    %0:_(i8) = G_IMPLICIT_DEF
+    %1:_(i8) = G_CONSTANT i8 15
+    %2:_(i8) = G_AND %0, %1
+    %3:_(i8) = G_CONSTANT i8 4
+    %4:_(i8) = G_UAVGFLOOR %2, %3
+...
+---
+name: Vector_UAvgFloor
+body: |
+  bb.0:
+  ; CHECK-LABEL: name: @Vector_UAvgFloor
+  ; CHECK-NEXT: %0:_ KnownBits:11001000 SignBits:2
+  ; CHECK-NEXT: %1:_ KnownBits:01100100 SignBits:1
+  ; CHECK-NEXT: %2:_ KnownBits:11001000 SignBits:2
+  ; CHECK-NEXT: %3:_ KnownBits:01100100 SignBits:1
+  ; CHECK-NEXT: %4:_ KnownBits:10010110 SignBits:1
+    %0:_(i8) = G_CONSTANT i8 200
+    %1:_(i8) = G_CONSTANT i8 100
+    %2:_(<2 x i8>) = G_BUILD_VECTOR %0, %0
+    %3:_(<2 x i8>) = G_BUILD_VECTOR %1, %1
+    %4:_(<2 x i8>) = G_UAVGFLOOR %2, %3
+...
+---
+name: Unknown_SAvgCeil
+body: |
+  bb.0:
+  ; CHECK-LABEL: name: @Unknown_SAvgCeil
+  ; CHECK-NEXT: %0:_ KnownBits:???????? SignBits:1
+  ; CHECK-NEXT: %1:_ KnownBits:???????? SignBits:1
+  ; CHECK-NEXT: %2:_ KnownBits:???????? SignBits:1
+    %0:_(i8) = COPY $b0
+    %1:_(i8) = COPY $b1
+    %2:_(i8) = G_SAVGCEIL %0, %1
+...
diff --git a/llvm/test/CodeGen/AArch64/aarch64-known-bits-hadd.ll b/llvm/test/CodeGen/AArch64/aarch64-known-bits-hadd.ll
index a6fbaf01c5476..d0a7cb2604ed2 100644
--- a/llvm/test/CodeGen/AArch64/aarch64-known-bits-hadd.ll
+++ b/llvm/test/CodeGen/AArch64/aarch64-known-bits-hadd.ll
@@ -18,9 +18,7 @@ define <8 x i16> @haddu_zext(<8 x i8> %a0, <8 x i8> %a1) {
 ; CHECK-GI:       // %bb.0:
 ; CHECK-GI-NEXT:    ushll v0.8h, v0.8b, #0
 ; CHECK-GI-NEXT:    ushll v1.8h, v1.8b, #0
-; CHECK-GI-NEXT:    mvni v2.8h, #254, lsl #8
 ; CHECK-GI-NEXT:    uhadd v0.8h, v0.8h, v1.8h
-; CHECK-GI-NEXT:    and v0.16b, v0.16b, v2.16b
 ; CHECK-GI-NEXT:    ret
   %x0 = zext <8 x i8> %a0 to <8 x i16>
   %x1 = zext <8 x i8> %a1 to <8 x i16>
@@ -40,9 +38,7 @@ define <8 x i16> @rhaddu_zext(<8 x i8> %a0, <8 x i8> %a1) {
 ; CHECK-GI:       // %bb.0:
 ; CHECK-GI-NEXT:    ushll v0.8h, v0.8b, #0
 ; CHECK-GI-NEXT:    ushll v1.8h, v1.8b, #0
-; CHECK-GI-NEXT:    mvni v2.8h, #254, lsl #8
 ; CHECK-GI-NEXT:    urhadd v0.8h, v0.8h, v1.8h
-; CHECK-GI-NEXT:    and v0.16b, v0.16b, v2.16b
 ; CHECK-GI-NEXT:    ret
   %x0 = zext <8 x i8> %a0 to <8 x i16>
   %x1 = zext <8 x i8> %a1 to <8 x i16>
@@ -62,9 +58,7 @@ define <8 x i16> @hadds_zext(<8 x i8> %a0, <8 x i8> %a1) {
 ; CHECK-GI:       // %bb.0:
 ; CHECK-GI-NEXT:    ushll v0.8h, v0.8b, #0
 ; CHECK-GI-NEXT:    ushll v1.8h, v1.8b, #0
-; CHECK-GI-NEXT:    mvni v2.8h, #254, lsl #8
 ; CHECK-GI-NEXT:    shadd v0.8h, v0.8h, v1.8h
-; CHECK-GI-NEXT:    and v0.16b, v0.16b, v2.16b
 ; CHECK-GI-NEXT:    ret
   %x0 = zext <8 x i8> %a0 to <8 x i16>
   %x1 = zext <8 x i8> %a1 to <8 x i16>
@@ -74,21 +68,12 @@ define <8 x i16> @hadds_zext(<8 x i8> %a0, <8 x i8> %a1) {
 }
 
 define <8 x i16> @shaddu_zext(<8 x i8> %a0, <8 x i8> %a1) {
-; CHECK-SD-LABEL: shaddu_zext:
-; CHECK-SD:       // %bb.0:
-; CHECK-SD-NEXT:    ushll v0.8h, v0.8b, #0
-; CHECK-SD-NEXT:    ushll v1.8h, v1.8b, #0
-; CHECK-SD-NEXT:    srhadd v0.8h, v0.8h, v1.8h
-; CHECK-SD-NEXT:    ret
-;
-; CHECK-GI-LABEL: shaddu_zext:
-; CHECK-GI:       // %bb.0:
-; CHECK-GI-NEXT:    ushll v0.8h, v0.8b, #0
-; CHECK-GI-NEXT:    ushll v1.8h, v1.8b, #0
-; CHECK-GI-NEXT:    mvni v2.8h, #254, lsl #8
-; CHECK-GI-NEXT:    srhadd v0.8h, v0.8h, v1.8h
-; CHECK-GI-NEXT:    and v0.16b, v0.16b, v2.16b
-; CHECK-GI-NEXT:    ret
+; CHECK-LABEL: shaddu_zext:
+; CHECK:       // %bb.0:
+; CHECK-NEXT:    ushll v0.8h, v0.8b, #0
+; CHECK-NEXT:    ushll v1.8h, v1.8b, #0
+; CHECK-NEXT:    srhadd v0.8h, v0.8h, v1.8h
+; CHECK-NEXT:    ret
   %x0 = zext <8 x i8> %a0 to <8 x i16>
   %x1 = zext <8 x i8> %a1 to <8 x i16>
   %hadd = call <8 x i16> @llvm.aarch64.neon.srhadd.v8i16(<8 x i16> %x0, <8 x i16> %x1)
@@ -191,5 +176,3 @@ define <8 x i16> @shaddu_sext(<8 x i8> %a0, <8 x i8> %a1) {
   %res = and <8 x i16> %hadd, <i16 511, i16 511, i16 511, i16 511, i16 511, i16 511, i16 511, i16 511>
   ret <8 x i16> %res
 }
-;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
-; CHECK: {{.*}}

``````````

</details>


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


More information about the llvm-commits mailing list