From 10d202e65caa9ed18ed423945ea0225a5d63895b Mon Sep 17 00:00:00 2001 From: ningxinr Date: Fri, 12 Sep 2025 12:05:03 -0700 Subject: [PATCH 01/10] Add tests for ISel and GlobalISel ADD --- .../AArch64/GlobalISel/knownbits-add.mir | 234 ++++++++++++++++++ .../AArch64/AArch64SelectionDAGTest.cpp | 94 +++++++ 2 files changed, 328 insertions(+) create mode 100644 llvm/test/CodeGen/AArch64/GlobalISel/knownbits-add.mir diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/knownbits-add.mir b/llvm/test/CodeGen/AArch64/GlobalISel/knownbits-add.mir new file mode 100644 index 0000000000000..352307fa6dd01 --- /dev/null +++ b/llvm/test/CodeGen/AArch64/GlobalISel/knownbits-add.mir @@ -0,0 +1,234 @@ +# NOTE: Assertions have been autogenerated by utils/update_givaluetracking_test_checks.py UTC_ARGS: --version 5 +# RUN: llc -mtriple aarch64 -passes="print" %s -o - 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: 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:1 + %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: 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:1 + %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 +... diff --git a/llvm/unittests/Target/AArch64/AArch64SelectionDAGTest.cpp b/llvm/unittests/Target/AArch64/AArch64SelectionDAGTest.cpp index 5ac4c53b71354..ed1348f4cda18 100644 --- a/llvm/unittests/Target/AArch64/AArch64SelectionDAGTest.cpp +++ b/llvm/unittests/Target/AArch64/AArch64SelectionDAGTest.cpp @@ -228,6 +228,100 @@ TEST_F(AArch64SelectionDAGTest, ComputeNumSignBits_SUB) { EXPECT_EQ(DAG->ComputeNumSignBits(Op), 2u); } +TEST_F(AArch64SelectionDAGTest, ComputeNumSignBits_ADD) { + SDLoc Loc; + auto IntVT = EVT::getIntegerVT(Context, 8); + auto Nneg1 = DAG->getConstant(0xFF, Loc, IntVT); + auto N0 = DAG->getConstant(0x00, Loc, IntVT); + auto N1 = DAG->getConstant(0x01, Loc, IntVT); + auto N5 = DAG->getConstant(0x05, Loc, IntVT); + auto Nsign1 = DAG->getConstant(0x55, Loc, IntVT); + auto UnknownOp = DAG->getRegister(0, IntVT); + auto Mask = DAG->getConstant(0x1e, Loc, IntVT); + auto Nsign3 = DAG->getNode(ISD::AND, Loc, IntVT, Mask, UnknownOp); + // RHS early out + // Nsign1 = 01010101 + // Nsign3 = 000????0 + auto OpRhsEo = DAG->getNode(ISD::ADD, Loc, IntVT, Nsign3, Nsign1); + EXPECT_EQ(DAG->ComputeNumSignBits(OpRhsEo), 1u); + + // ADD 0 -1 + // N0 = 00000000 + // Nneg1 = 11111111 + auto OpNegZero = DAG->getNode(ISD::ADD, Loc, IntVT, N0, Nneg1); + EXPECT_EQ(DAG->ComputeNumSignBits(OpNegZero), 8u); + + // ADD 1 -1 + // N1 = 00000001 + // Nneg1 = 11111111 + auto OpNegOne = DAG->getNode(ISD::ADD, Loc, IntVT, N1, Nneg1); + EXPECT_EQ(DAG->ComputeNumSignBits(OpNegOne), 8u); + + // Non negative + // Nsign3 = 000????0 + // Nneg1 = 11111111 + auto OpNonNeg = DAG->getNode(ISD::ADD, Loc, IntVT, Nsign3, Nneg1); + EXPECT_EQ(DAG->ComputeNumSignBits(OpNonNeg), 3u); + + // LHS early out + // Nsign1 = 01010101 + // Nsign3 = 000????0 + auto OpLhsEo = DAG->getNode(ISD::ADD, Loc, IntVT, Nsign1, Nsign3); + EXPECT_EQ(DAG->ComputeNumSignBits(OpLhsEo), 1u); + + // Nsign3 = 000????0 + // N5 = 00000101 + auto Op = DAG->getNode(ISD::ADD, Loc, IntVT, Nsign3, N5); + EXPECT_EQ(DAG->ComputeNumSignBits(Op), 2u); +} + +TEST_F(AArch64SelectionDAGTest, ComputeNumSignBits_ADDC) { + SDLoc Loc; + auto IntVT = EVT::getIntegerVT(Context, 8); + auto Nneg1 = DAG->getConstant(0xFF, Loc, IntVT); + auto N0 = DAG->getConstant(0x00, Loc, IntVT); + auto N1 = DAG->getConstant(0x01, Loc, IntVT); + auto N5 = DAG->getConstant(0x05, Loc, IntVT); + auto Nsign1 = DAG->getConstant(0x55, Loc, IntVT); + auto UnknownOp = DAG->getRegister(0, IntVT); + auto Mask = DAG->getConstant(0x1e, Loc, IntVT); + auto Nsign3 = DAG->getNode(ISD::AND, Loc, IntVT, Mask, UnknownOp); + // RHS early out + // Nsign1 = 01010101 + // Nsign3 = 000????0 + auto OpRhsEo = DAG->getNode(ISD::ADDC, Loc, IntVT, Nsign3, Nsign1); + EXPECT_EQ(DAG->ComputeNumSignBits(OpRhsEo), 1u); + + // ADD 0 -1 + // N0 = 00000000 + // Nneg1 = 11111111 + auto OpNegZero = DAG->getNode(ISD::ADDC, Loc, IntVT, N0, Nneg1); + EXPECT_EQ(DAG->ComputeNumSignBits(OpNegZero), 8u); + + // ADD 1 -1 + // N1 = 00000001 + // Nneg1 = 11111111 + auto OpNegOne = DAG->getNode(ISD::ADDC, Loc, IntVT, N1, Nneg1); + EXPECT_EQ(DAG->ComputeNumSignBits(OpNegOne), 8u); + + // Non negative + // Nsign3 = 000????0 + // Nneg1 = 11111111 + auto OpNonNeg = DAG->getNode(ISD::ADDC, Loc, IntVT, Nsign3, Nneg1); + EXPECT_EQ(DAG->ComputeNumSignBits(OpNonNeg), 3u); + + // LHS early out + // Nsign1 = 01010101 + // Nsign3 = 000????0 + auto OpLhsEo = DAG->getNode(ISD::ADDC, Loc, IntVT, Nsign1, Nsign3); + EXPECT_EQ(DAG->ComputeNumSignBits(OpLhsEo), 1u); + + // Nsign3 = 000????0 + // N5 = 00000101 + auto Op = DAG->getNode(ISD::ADDC, Loc, IntVT, Nsign3, N5); + EXPECT_EQ(DAG->ComputeNumSignBits(Op), 2u); +} + TEST_F(AArch64SelectionDAGTest, SimplifyDemandedVectorElts_EXTRACT_SUBVECTOR) { TargetLowering TL(*TM); From 719bfc299634e5f9b9bb691c58487b21aa5e0303 Mon Sep 17 00:00:00 2001 From: ningxinr Date: Fri, 12 Sep 2025 16:19:38 -0700 Subject: [PATCH 02/10] Initial attemp for ADD --- llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp | 14 ++++++++++++++ .../CodeGen/AArch64/GlobalISel/knownbits-add.mir | 4 ++-- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp b/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp index 3812823f9fffa..5f0ffe2487246 100644 --- a/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp +++ b/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp @@ -2013,6 +2013,20 @@ unsigned GISelValueTracking::computeNumSignBits(Register R, FirstAnswer = std::min(Src1NumSignBits, Src2NumSignBits) - 1; break; } + case TargetOpcode::G_ADD: { + Register Src1 = MI.getOperand(1).getReg(); + unsigned Src1NumSignBits = + computeNumSignBits(Src1, DemandedElts, Depth + 1); + if (Src1NumSignBits != 1) { + Register Src2 = MI.getOperand(2).getReg(); + unsigned Src2NumSignBits = + computeNumSignBits(Src2, DemandedElts, Depth + 1); + if (Src2NumSignBits == 1) + return 1; // Early out. + FirstAnswer = std::min(Src1NumSignBits, Src2NumSignBits) - 1; + } + break; + } case TargetOpcode::G_FCMP: case TargetOpcode::G_ICMP: { bool IsFP = Opcode == TargetOpcode::G_FCMP; diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/knownbits-add.mir b/llvm/test/CodeGen/AArch64/GlobalISel/knownbits-add.mir index 352307fa6dd01..9a5fe2192f5f2 100644 --- a/llvm/test/CodeGen/AArch64/GlobalISel/knownbits-add.mir +++ b/llvm/test/CodeGen/AArch64/GlobalISel/knownbits-add.mir @@ -82,7 +82,7 @@ body: | ; 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:1 + ; CHECK-NEXT: %4:_ KnownBits:???????? SignBits:3 %0:_(s8) = COPY $b0 %1:_(s8) = G_CONSTANT i8 15 %2:_(s8) = G_AND %0, %1 @@ -154,7 +154,7 @@ body: | ; 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:1 + ; CHECK-NEXT: %6:_ KnownBits:???????????????? 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 From f9a6e44bd13d582e583c850391259ee28ce01552 Mon Sep 17 00:00:00 2001 From: ningxinr Date: Mon, 15 Sep 2025 11:10:05 -0700 Subject: [PATCH 03/10] Handle non neg case --- .../CodeGen/GlobalISel/GISelValueTracking.cpp | 35 +++++++++++++++---- .../lib/CodeGen/SelectionDAG/SelectionDAG.cpp | 6 ++-- .../AArch64/GlobalISel/knownbits-add.mir | 4 +-- 3 files changed, 34 insertions(+), 11 deletions(-) diff --git a/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp b/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp index 5f0ffe2487246..f03000bd4bc11 100644 --- a/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp +++ b/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp @@ -2014,17 +2014,38 @@ unsigned GISelValueTracking::computeNumSignBits(Register R, break; } case TargetOpcode::G_ADD: { + Register Src2 = MI.getOperand(2).getReg(); + unsigned Src2NumSignBits = + computeNumSignBits(Src2, DemandedElts, Depth + 1); + if (Src2NumSignBits == 1) + return 1; // Early out. + Register Src1 = MI.getOperand(1).getReg(); unsigned Src1NumSignBits = computeNumSignBits(Src1, DemandedElts, Depth + 1); - if (Src1NumSignBits != 1) { - Register Src2 = MI.getOperand(2).getReg(); - unsigned Src2NumSignBits = - computeNumSignBits(Src2, DemandedElts, Depth + 1); - if (Src2NumSignBits == 1) - return 1; // Early out. - FirstAnswer = std::min(Src1NumSignBits, Src2NumSignBits) - 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 the input is known to be positive (the sign bit is known clear), + // the output of the NEG has the same number of sign bits as the input. + if (Known1.isNonNegative()) + return Src1NumSignBits; + + // Otherwise, we treat this like an ADD. } + + // 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: diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp index 2b8dd60870696..5a923660eda75 100644 --- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp @@ -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. @@ -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); diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/knownbits-add.mir b/llvm/test/CodeGen/AArch64/GlobalISel/knownbits-add.mir index 9a5fe2192f5f2..f4f057e92633f 100644 --- a/llvm/test/CodeGen/AArch64/GlobalISel/knownbits-add.mir +++ b/llvm/test/CodeGen/AArch64/GlobalISel/knownbits-add.mir @@ -82,7 +82,7 @@ body: | ; 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:3 + ; CHECK-NEXT: %4:_ KnownBits:???????? SignBits:4 %0:_(s8) = COPY $b0 %1:_(s8) = G_CONSTANT i8 15 %2:_(s8) = G_AND %0, %1 @@ -154,7 +154,7 @@ body: | ; 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:7 + ; 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 From bfa62cfabc5a613a260b3967802c5feccdbafd67 Mon Sep 17 00:00:00 2001 From: Yatao Wang Date: Mon, 29 Sep 2025 15:39:48 -0700 Subject: [PATCH 04/10] Apply suggestions from code review Co-authored-by: Matt Arsenault --- llvm/test/CodeGen/AArch64/GlobalISel/knownbits-add.mir | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/knownbits-add.mir b/llvm/test/CodeGen/AArch64/GlobalISel/knownbits-add.mir index f4f057e92633f..248dde8e9bdc6 100644 --- a/llvm/test/CodeGen/AArch64/GlobalISel/knownbits-add.mir +++ b/llvm/test/CodeGen/AArch64/GlobalISel/knownbits-add.mir @@ -1,5 +1,5 @@ # NOTE: Assertions have been autogenerated by utils/update_givaluetracking_test_checks.py UTC_ARGS: --version 5 -# RUN: llc -mtriple aarch64 -passes="print" %s -o - 2>&1 | FileCheck %s +# RUN: llc -mtriple=aarch64 -passes='print' -filetype=null %s 2>&1 | FileCheck %s --- name: Cst From 2cd4378bb29f94263c876c31a99aeca81ddafad1 Mon Sep 17 00:00:00 2001 From: ningxinr Date: Mon, 29 Sep 2025 16:04:37 -0700 Subject: [PATCH 05/10] Added Cst Zero test and Cst Neg One test for vector --- .../AArch64/GlobalISel/knownbits-add.mir | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/knownbits-add.mir b/llvm/test/CodeGen/AArch64/GlobalISel/knownbits-add.mir index 248dde8e9bdc6..c011ce7fdb963 100644 --- a/llvm/test/CodeGen/AArch64/GlobalISel/knownbits-add.mir +++ b/llvm/test/CodeGen/AArch64/GlobalISel/knownbits-add.mir @@ -118,6 +118,38 @@ body: | %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: From 68aa6ebc6a4c7bf1f2235b77bd4a6067a7891e38 Mon Sep 17 00:00:00 2001 From: ningxinr Date: Wed, 1 Oct 2025 09:13:13 -0700 Subject: [PATCH 06/10] Addressed feedback --- llvm/test/CodeGen/AArch64/GlobalISel/knownbits-add.mir | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/knownbits-add.mir b/llvm/test/CodeGen/AArch64/GlobalISel/knownbits-add.mir index c011ce7fdb963..d38fbd9aed085 100644 --- a/llvm/test/CodeGen/AArch64/GlobalISel/knownbits-add.mir +++ b/llvm/test/CodeGen/AArch64/GlobalISel/knownbits-add.mir @@ -1,5 +1,5 @@ # NOTE: Assertions have been autogenerated by utils/update_givaluetracking_test_checks.py UTC_ARGS: --version 5 -# RUN: llc -mtriple=aarch64 -passes='print' -filetype=null %s 2>&1 | FileCheck %s +# RUN: llc -mtriple=aarch64 -passes="print" -filetype=null %s 2>&1 | FileCheck %s --- name: Cst From 5052ca870b773a020e7ca7c3355bae87c30f613b Mon Sep 17 00:00:00 2001 From: ningxinr Date: Tue, 7 Oct 2025 10:33:09 -0700 Subject: [PATCH 07/10] Fixed copy pasta --- llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp b/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp index f03000bd4bc11..f818d57ac8c87 100644 --- a/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp +++ b/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp @@ -2035,8 +2035,8 @@ unsigned GISelValueTracking::computeNumSignBits(Register R, if ((Known1.Zero | 1).isAllOnes()) return TyBits; - // If the input is known to be positive (the sign bit is known clear), - // the output of the NEG has the same number of sign bits as the input. + // If we are subtracting one from a positive number, there is no carry + // out of the result. if (Known1.isNonNegative()) return Src1NumSignBits; From 746dec010df80332d2bab02d3647fd2c557ff6dd Mon Sep 17 00:00:00 2001 From: ningxinr Date: Tue, 7 Oct 2025 10:36:29 -0700 Subject: [PATCH 08/10] Addressed feedback --- llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp b/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp index f818d57ac8c87..3cb81e696978f 100644 --- a/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp +++ b/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp @@ -2017,7 +2017,7 @@ unsigned GISelValueTracking::computeNumSignBits(Register R, Register Src2 = MI.getOperand(2).getReg(); unsigned Src2NumSignBits = computeNumSignBits(Src2, DemandedElts, Depth + 1); - if (Src2NumSignBits == 1) + if (Src2NumSignBits <= 2) return 1; // Early out. Register Src1 = MI.getOperand(1).getReg(); From 0cd1a4f651b91da4ad5598fafc510c38fca7957b Mon Sep 17 00:00:00 2001 From: ningxinr Date: Tue, 7 Oct 2025 15:53:10 -0700 Subject: [PATCH 09/10] Improved handling when LHS is constant and RHS is -1 --- llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp | 6 ++++-- .../CodeGen/AArch64/GlobalISel/knownbits-add.mir | 12 ++++++++++++ .../Target/AArch64/AArch64SelectionDAGTest.cpp | 7 +++++++ 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp b/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp index 3cb81e696978f..9b9a6a2513f54 100644 --- a/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp +++ b/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp @@ -2037,8 +2037,10 @@ unsigned GISelValueTracking::computeNumSignBits(Register R, // If we are subtracting one from a positive number, there is no carry // out of the result. - if (Known1.isNonNegative()) - return Src1NumSignBits; + if (Known1.isNonNegative()) { + FirstAnswer = Src1NumSignBits; + break; + } // Otherwise, we treat this like an ADD. } diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/knownbits-add.mir b/llvm/test/CodeGen/AArch64/GlobalISel/knownbits-add.mir index d38fbd9aed085..824ada1cf4a05 100644 --- a/llvm/test/CodeGen/AArch64/GlobalISel/knownbits-add.mir +++ b/llvm/test/CodeGen/AArch64/GlobalISel/knownbits-add.mir @@ -38,6 +38,18 @@ body: | %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: diff --git a/llvm/unittests/Target/AArch64/AArch64SelectionDAGTest.cpp b/llvm/unittests/Target/AArch64/AArch64SelectionDAGTest.cpp index ed1348f4cda18..2aeb8de6f431f 100644 --- a/llvm/unittests/Target/AArch64/AArch64SelectionDAGTest.cpp +++ b/llvm/unittests/Target/AArch64/AArch64SelectionDAGTest.cpp @@ -235,6 +235,7 @@ TEST_F(AArch64SelectionDAGTest, ComputeNumSignBits_ADD) { auto N0 = DAG->getConstant(0x00, Loc, IntVT); auto N1 = DAG->getConstant(0x01, Loc, IntVT); auto N5 = DAG->getConstant(0x05, Loc, IntVT); + auto N8 = DAG->getConstant(0x08, Loc, IntVT); auto Nsign1 = DAG->getConstant(0x55, Loc, IntVT); auto UnknownOp = DAG->getRegister(0, IntVT); auto Mask = DAG->getConstant(0x1e, Loc, IntVT); @@ -257,6 +258,12 @@ TEST_F(AArch64SelectionDAGTest, ComputeNumSignBits_ADD) { auto OpNegOne = DAG->getNode(ISD::ADD, Loc, IntVT, N1, Nneg1); EXPECT_EQ(DAG->ComputeNumSignBits(OpNegOne), 8u); + // ADD 8 -1 + // N8 = 00001000 + // Nneg1 = 11111111 + auto OpSeven = DAG->getNode(ISD::ADD, Loc, IntVT, N8, Nneg1); + EXPECT_EQ(DAG->ComputeNumSignBits(OpSeven), 5u); + // Non negative // Nsign3 = 000????0 // Nneg1 = 11111111 From 155153cf1e6f62c48ff8fb5a05ec28c26ed9e593 Mon Sep 17 00:00:00 2001 From: ningxinr Date: Mon, 13 Oct 2025 12:57:08 -0700 Subject: [PATCH 10/10] Add ADDC(Const, -1) test for ADDC --- llvm/unittests/Target/AArch64/AArch64SelectionDAGTest.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/llvm/unittests/Target/AArch64/AArch64SelectionDAGTest.cpp b/llvm/unittests/Target/AArch64/AArch64SelectionDAGTest.cpp index 2aeb8de6f431f..809960d368e4e 100644 --- a/llvm/unittests/Target/AArch64/AArch64SelectionDAGTest.cpp +++ b/llvm/unittests/Target/AArch64/AArch64SelectionDAGTest.cpp @@ -289,6 +289,7 @@ TEST_F(AArch64SelectionDAGTest, ComputeNumSignBits_ADDC) { auto N0 = DAG->getConstant(0x00, Loc, IntVT); auto N1 = DAG->getConstant(0x01, Loc, IntVT); auto N5 = DAG->getConstant(0x05, Loc, IntVT); + auto N8 = DAG->getConstant(0x08, Loc, IntVT); auto Nsign1 = DAG->getConstant(0x55, Loc, IntVT); auto UnknownOp = DAG->getRegister(0, IntVT); auto Mask = DAG->getConstant(0x1e, Loc, IntVT); @@ -311,6 +312,12 @@ TEST_F(AArch64SelectionDAGTest, ComputeNumSignBits_ADDC) { auto OpNegOne = DAG->getNode(ISD::ADDC, Loc, IntVT, N1, Nneg1); EXPECT_EQ(DAG->ComputeNumSignBits(OpNegOne), 8u); + // ADD 8 -1 + // N8 = 00001000 + // Nneg1 = 11111111 + auto OpSeven = DAG->getNode(ISD::ADDC, Loc, IntVT, N8, Nneg1); + EXPECT_EQ(DAG->ComputeNumSignBits(OpSeven), 4u); + // Non negative // Nsign3 = 000????0 // Nneg1 = 11111111