Skip to content
Merged
37 changes: 37 additions & 0 deletions llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2013,6 +2013,43 @@ unsigned GISelValueTracking::computeNumSignBits(Register R,
FirstAnswer = std::min(Src1NumSignBits, Src2NumSignBits) - 1;
break;
}
case TargetOpcode::G_ADD: {
Register Src2 = MI.getOperand(2).getReg();
unsigned Src2NumSignBits =
computeNumSignBits(Src2, DemandedElts, Depth + 1);
if (Src2NumSignBits <= 2)
return 1; // Early out.

Register Src1 = MI.getOperand(1).getReg();
unsigned Src1NumSignBits =
computeNumSignBits(Src1, DemandedElts, Depth + 1);
if (Src1NumSignBits == 1)
return 1; // Early Out.

// Special case decrementing a value (ADD X, -1):
KnownBits Known2 = getKnownBits(Src2, DemandedElts, Depth);
if (Known2.isAllOnes()) {
KnownBits Known1 = getKnownBits(Src1, DemandedElts, Depth);
// If the input is known to be 0 or 1, the output is 0/-1, which is all
// sign bits set.
if ((Known1.Zero | 1).isAllOnes())
return TyBits;

// If we are subtracting one from a positive number, there is no carry
// out of the result.
if (Known1.isNonNegative()) {
FirstAnswer = Src1NumSignBits;
break;
}

// Otherwise, we treat this like an ADD.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In a follow up can add the carry out cases

Copy link
Contributor Author

@ningxinr ningxinr Sep 29, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will do!

What should we do about the carry out cases here? Is there an example I can follow?

I am asking because neither cases of ISD::ADD/ISD::ADDC in SelectionDAG::ComputeNumSignBits nor Global ISel Generic Opcode Doc mentions anything about the carry out cases. (Also David mentioned in issue #150515 that ADDC node is deprecated in GlobalISel. Does that mean ADD always carry in GlobalISel?)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, there are explicit uaddo_carry / saddo_carry. The DAG has the same, they just use explicit virtual register outputs instead of glue

Copy link
Contributor Author

@ningxinr ningxinr Oct 8, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah thanks for the clarification!

Are you referring to this part that handles carry in SelectionDAG, but not implemented in GlobalISel?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes

}

// Add can have at most one carry bit. Thus we know that the output
// is, at worst, one more bit than the inputs.
FirstAnswer = std::min(Src1NumSignBits, Src2NumSignBits) - 1;
break;
}
case TargetOpcode::G_FCMP:
case TargetOpcode::G_ICMP: {
bool IsFP = Opcode == TargetOpcode::G_FCMP;
Expand Down
6 changes: 4 additions & 2 deletions llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5063,8 +5063,7 @@ unsigned SelectionDAG::ComputeNumSignBits(SDValue Op, const APInt &DemandedElts,
break;
case ISD::ADD:
case ISD::ADDC:
// Add can have at most one carry bit. Thus we know that the output
// is, at worst, one more bit than the inputs.
// TODO: Move Operand 1 check before Operand 0 check
Tmp = ComputeNumSignBits(Op.getOperand(0), DemandedElts, Depth + 1);
if (Tmp == 1) return 1; // Early out.

Expand All @@ -5088,6 +5087,9 @@ unsigned SelectionDAG::ComputeNumSignBits(SDValue Op, const APInt &DemandedElts,

Tmp2 = ComputeNumSignBits(Op.getOperand(1), DemandedElts, Depth + 1);
if (Tmp2 == 1) return 1; // Early out.

// Add can have at most one carry bit. Thus we know that the output
// is, at worst, one more bit than the inputs.
return std::min(Tmp, Tmp2) - 1;
case ISD::SUB:
Tmp2 = ComputeNumSignBits(Op.getOperand(1), DemandedElts, Depth + 1);
Expand Down
278 changes: 278 additions & 0 deletions llvm/test/CodeGen/AArch64/GlobalISel/knownbits-add.mir
Original file line number Diff line number Diff line change
@@ -0,0 +1,278 @@
# NOTE: Assertions have been autogenerated by utils/update_givaluetracking_test_checks.py UTC_ARGS: --version 5
# RUN: llc -mtriple=aarch64 -passes="print<gisel-value-tracking>" -filetype=null %s 2>&1 | FileCheck %s

---
name: Cst
body: |
bb.1:
; CHECK-LABEL: name: @Cst
; CHECK-NEXT: %0:_ KnownBits:00000010 SignBits:6
; CHECK-NEXT: %1:_ KnownBits:00011000 SignBits:3
; CHECK-NEXT: %2:_ KnownBits:00011010 SignBits:3
%0:_(s8) = G_CONSTANT i8 2
%1:_(s8) = G_CONSTANT i8 24
%2:_(s8) = G_ADD %0, %1
...
---
name: CstZero
body: |
bb.1:
; CHECK-LABEL: name: @CstZero
; CHECK-NEXT: %0:_ KnownBits:00000001 SignBits:7
; CHECK-NEXT: %1:_ KnownBits:11111111 SignBits:8
; CHECK-NEXT: %2:_ KnownBits:00000000 SignBits:8
%0:_(s8) = G_CONSTANT i8 1
%1:_(s8) = G_CONSTANT i8 255
%2:_(s8) = G_ADD %0, %1
...
---
name: CstNegOne
body: |
bb.1:
; CHECK-LABEL: name: @CstNegOne
; CHECK-NEXT: %0:_ KnownBits:00000000 SignBits:8
; CHECK-NEXT: %1:_ KnownBits:11111111 SignBits:8
; CHECK-NEXT: %2:_ KnownBits:11111111 SignBits:8
%0:_(s8) = G_CONSTANT i8 0
%1:_(s8) = G_CONSTANT i8 255
%2:_(s8) = G_ADD %0, %1
...
---
name: CstSeven
body: |
bb.1:
; CHECK-LABEL: name: @CstSeven
; CHECK-NEXT: %0:_ KnownBits:00001000 SignBits:4
; CHECK-NEXT: %1:_ KnownBits:11111111 SignBits:8
; CHECK-NEXT: %2:_ KnownBits:00000111 SignBits:5
%0:_(s8) = G_CONSTANT i8 8
%1:_(s8) = G_CONSTANT i8 255
%2:_(s8) = G_ADD %0, %1
...
---
name: CstNeg
body: |
bb.1:
; CHECK-LABEL: name: @CstNeg
; CHECK-NEXT: %0:_ KnownBits:11100000 SignBits:3
; CHECK-NEXT: %1:_ KnownBits:00000010 SignBits:6
; CHECK-NEXT: %2:_ KnownBits:11100010 SignBits:3
%0:_(s8) = G_CONSTANT i8 224
%1:_(s8) = G_CONSTANT i8 2
%2:_(s8) = G_ADD %0, %1
...
---
name: ScalarVar
body: |
bb.1:
; CHECK-LABEL: name: @ScalarVar
; CHECK-NEXT: %0:_ KnownBits:???????? SignBits:1
; CHECK-NEXT: %1:_ KnownBits:???????? SignBits:1
; CHECK-NEXT: %2:_ KnownBits:???????? SignBits:1
%0:_(s8) = COPY $b0
%1:_(s8) = COPY $b1
%2:_(s8) = G_ADD %0, %1
...
---
name: ScalarRhsEarlyOut
body: |
bb.1:
; CHECK-LABEL: name: @ScalarRhsEarlyOut
; CHECK-NEXT: %0:_ KnownBits:???????? SignBits:1
; CHECK-NEXT: %1:_ KnownBits:00000011 SignBits:6
; CHECK-NEXT: %2:_ KnownBits:???????? SignBits:1
%0:_(s8) = COPY $b0
%1:_(s8) = G_CONSTANT i8 3
%2:_(s8) = G_ADD %0, %1
...
---
name: ScalarNonNegative
body: |
bb.1:
; CHECK-LABEL: name: @ScalarNonNegative
; CHECK-NEXT: %0:_ KnownBits:???????? SignBits:1
; CHECK-NEXT: %1:_ KnownBits:00001111 SignBits:4
; CHECK-NEXT: %2:_ KnownBits:0000???? SignBits:4
; CHECK-NEXT: %3:_ KnownBits:11111111 SignBits:8
; CHECK-NEXT: %4:_ KnownBits:???????? SignBits:4
%0:_(s8) = COPY $b0
%1:_(s8) = G_CONSTANT i8 15
%2:_(s8) = G_AND %0, %1
%3:_(s8) = G_CONSTANT i8 255
%4:_(s8) = G_ADD %2, %3
...
---
name: ScalarLhsEarlyOut
body: |
bb.1:
; CHECK-LABEL: name: @ScalarLhsEarlyOut
; CHECK-NEXT: %0:_ KnownBits:???????? SignBits:1
; CHECK-NEXT: %1:_ KnownBits:00000011 SignBits:6
; CHECK-NEXT: %2:_ KnownBits:???????? SignBits:1
%0:_(s8) = COPY $b0
%1:_(s8) = G_CONSTANT i8 3
%2:_(s8) = G_ADD %1, %0
...
---
name: ScalarPartKnown
body: |
bb.1:
; CHECK-LABEL: name: @ScalarPartKnown
; CHECK-NEXT: %0:_ KnownBits:???????? SignBits:1
; CHECK-NEXT: %1:_ KnownBits:00001111 SignBits:4
; CHECK-NEXT: %2:_ KnownBits:0000???? SignBits:4
; CHECK-NEXT: %3:_ KnownBits:00000101 SignBits:5
; CHECK-NEXT: %4:_ KnownBits:000????? SignBits:3
%0:_(s8) = COPY $b0
%1:_(s8) = G_CONSTANT i8 15
%2:_(s8) = G_AND %0, %1
%3:_(s8) = G_CONSTANT i8 5
%4:_(s8) = G_ADD %2, %3
...
---
name: VectorCstZero
body: |
bb.1:
; CHECK-LABEL: name: @VectorCstZero
; CHECK-NEXT: %0:_ KnownBits:0000000000000001 SignBits:15
; CHECK-NEXT: %1:_ KnownBits:1111111111111111 SignBits:16
; CHECK-NEXT: %2:_ KnownBits:0000000000000001 SignBits:15
; CHECK-NEXT: %3:_ KnownBits:1111111111111111 SignBits:16
; CHECK-NEXT: %4:_ KnownBits:0000000000000000 SignBits:16
%0:_(s16) = G_CONSTANT i16 1
%1:_(s16) = G_CONSTANT i16 65535
%2:_(<4 x s16>) = G_BUILD_VECTOR %0, %0, %0, %0
%3:_(<4 x s16>) = G_BUILD_VECTOR %1, %1, %1, %1
%4:_(<4 x s16>) = G_ADD %2, %3
...
---
name: VectorCstNegOne
body: |
bb.1:
; CHECK-LABEL: name: @VectorCstNegOne
; CHECK-NEXT: %0:_ KnownBits:0000000000000000 SignBits:16
; CHECK-NEXT: %1:_ KnownBits:1111111111111111 SignBits:16
; CHECK-NEXT: %2:_ KnownBits:0000000000000000 SignBits:16
; CHECK-NEXT: %3:_ KnownBits:1111111111111111 SignBits:16
; CHECK-NEXT: %4:_ KnownBits:1111111111111111 SignBits:16
%0:_(s16) = G_CONSTANT i16 0
%1:_(s16) = G_CONSTANT i16 65535
%2:_(<4 x s16>) = G_BUILD_VECTOR %0, %0, %0, %0
%3:_(<4 x s16>) = G_BUILD_VECTOR %1, %1, %1, %1
%4:_(<4 x s16>) = G_ADD %2, %3
...
---
name: VectorVar
body: |
bb.1:
; CHECK-LABEL: name: @VectorVar
; CHECK-NEXT: %0:_ KnownBits:???????????????? SignBits:1
; CHECK-NEXT: %1:_ KnownBits:???????????????? SignBits:1
; CHECK-NEXT: %2:_ KnownBits:???????????????? SignBits:1
%0:_(<4 x s16>) = COPY $d0
%1:_(<4 x s16>) = COPY $d1
%2:_(<4 x s16>) = G_ADD %0, %1
...
---
name: VectorRhsEarlyOut
body: |
bb.1:
; CHECK-LABEL: name: @VectorRhsEarlyOut
; CHECK-NEXT: %0:_ KnownBits:???????????????? SignBits:1
; CHECK-NEXT: %1:_ KnownBits:0000000000000011 SignBits:14
; CHECK-NEXT: %2:_ KnownBits:0000000000000011 SignBits:14
; CHECK-NEXT: %3:_ KnownBits:???????????????? SignBits:1
%0:_(<4 x s16>) = COPY $d0
%1:_(s16) = G_CONSTANT i16 3
%2:_(<4 x s16>) = G_BUILD_VECTOR %1, %1, %1, %1
%3:_(<4 x s16>) = G_ADD %2, %0
...
---
name: VectorNonNegative
body: |
bb.1:
; CHECK-LABEL: name: @VectorNonNegative
; CHECK-NEXT: %0:_ KnownBits:???????????????? SignBits:1
; CHECK-NEXT: %1:_ KnownBits:0000000011111111 SignBits:8
; CHECK-NEXT: %2:_ KnownBits:0000000011111111 SignBits:8
; CHECK-NEXT: %3:_ KnownBits:00000000???????? SignBits:8
; CHECK-NEXT: %4:_ KnownBits:1111111111111111 SignBits:16
; CHECK-NEXT: %5:_ KnownBits:1111111111111111 SignBits:16
; CHECK-NEXT: %6:_ KnownBits:???????????????? SignBits:8
%0:_(<4 x s16>) = COPY $d0
%1:_(s16) = G_CONSTANT i16 255
%2:_(<4 x s16>) = G_BUILD_VECTOR %1, %1, %1, %1
%3:_(<4 x s16>) = G_AND %0, %2
%4:_(s16) = G_CONSTANT i16 65535
%5:_(<4 x s16>) = G_BUILD_VECTOR %4, %4, %4, %4
%6:_(<4 x s16>) = G_ADD %3, %5
...
---
name: VectorLhsEarlyOut
body: |
bb.1:
; CHECK-LABEL: name: @VectorLhsEarlyOut
; CHECK-NEXT: %0:_ KnownBits:???????????????? SignBits:1
; CHECK-NEXT: %1:_ KnownBits:0000000000000011 SignBits:14
; CHECK-NEXT: %2:_ KnownBits:0000000000000011 SignBits:14
; CHECK-NEXT: %3:_ KnownBits:???????????????? SignBits:1
%0:_(<4 x s16>) = COPY $d0
%1:_(s16) = G_CONSTANT i16 3
%2:_(<4 x s16>) = G_BUILD_VECTOR %1, %1, %1, %1
%3:_(<4 x s16>) = G_ADD %0, %2
...
---
name: VectorPartKnown
body: |
bb.1:
; CHECK-LABEL: name: @VectorPartKnown
; CHECK-NEXT: %0:_ KnownBits:???????????????? SignBits:1
; CHECK-NEXT: %1:_ KnownBits:0000000011111111 SignBits:8
; CHECK-NEXT: %2:_ KnownBits:0000000011111111 SignBits:8
; CHECK-NEXT: %3:_ KnownBits:00000000???????? SignBits:8
; CHECK-NEXT: %4:_ KnownBits:0000000000101010 SignBits:10
; CHECK-NEXT: %5:_ KnownBits:0000000001001010 SignBits:9
; CHECK-NEXT: %6:_ KnownBits:000000000??01010 SignBits:9
; CHECK-NEXT: %7:_ KnownBits:0000000????????? SignBits:7
%0:_(<4 x s16>) = COPY $d0
%1:_(s16) = G_CONSTANT i16 255
%2:_(<4 x s16>) = G_BUILD_VECTOR %1, %1, %1, %1
%3:_(<4 x s16>) = G_AND %0, %2
%4:_(s16) = G_CONSTANT i16 42
%5:_(s16) = G_CONSTANT i16 74
%6:_(<4 x s16>) = G_BUILD_VECTOR %4, %5, %5, %4
%7:_(<4 x s16>) = G_ADD %6, %3
...
---
name: VectorCst36
body: |
bb.1:
; CHECK-LABEL: name: @VectorCst36
; CHECK-NEXT: %0:_ KnownBits:0000000000000011 SignBits:14
; CHECK-NEXT: %1:_ KnownBits:0000000000000110 SignBits:13
; CHECK-NEXT: %2:_ KnownBits:0000000000000?1? SignBits:13
; CHECK-NEXT: %3:_ KnownBits:0000000000000?1? SignBits:13
; CHECK-NEXT: %4:_ KnownBits:000000000000???? SignBits:12
%0:_(s16) = G_CONSTANT i16 3
%1:_(s16) = G_CONSTANT i16 6
%2:_(<4 x s16>) = G_BUILD_VECTOR %0, %1, %1, %0
%3:_(<4 x s16>) = G_BUILD_VECTOR %0, %1, %1, %0
%4:_(<4 x s16>) = G_ADD %2, %3
...

---
name: VectorCst3unknown
body: |
bb.1:
; CHECK-LABEL: name: @VectorCst3unknown
; CHECK-NEXT: %0:_ KnownBits:???????????????? SignBits:1
; CHECK-NEXT: %1:_ KnownBits:???????????????? SignBits:1
; CHECK-NEXT: %2:_ KnownBits:0000000000000011 SignBits:14
; CHECK-NEXT: %3:_ KnownBits:???????????????? SignBits:1
; CHECK-NEXT: %4:_ KnownBits:???????????????? SignBits:1
%0:_(<4 x s16>) = COPY $d0
%1:_(s16) = COPY $h0
%2:_(s16) = G_CONSTANT i16 3
%3:_(<4 x s16>) = G_BUILD_VECTOR %1, %2, %2, %1
%4:_(<4 x s16>) = G_ADD %0, %3
...
Loading
Loading