Skip to content

Commit

Permalink
[ValueTracking] Known bits support for unsigned saturating add/sub
Browse files Browse the repository at this point in the history
We have two sources of known bits:

1. For adds leading ones of either operand are preserved. For sub
leading zeros of LHS and leading ones of RHS become leading zeros in
the result.

2. The saturating math is a select between add/sub and an all-ones/
zero value. As such we can carry out the add/sub known bits
calculation, and only preseve the known one/zero bits respectively.

Differential Revision: https://reviews.llvm.org/D58329

llvm-svn: 355223
  • Loading branch information
nikic committed Mar 1, 2019
1 parent cf0a978 commit ed3ca92
Show file tree
Hide file tree
Showing 2 changed files with 102 additions and 0 deletions.
31 changes: 31 additions & 0 deletions llvm/lib/Analysis/ValueTracking.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1523,6 +1523,37 @@ static void computeKnownBitsFromOperator(const Operator *I, KnownBits &Known,
Known2.One.shl(ShiftAmt) | Known3.One.lshr(BitWidth - ShiftAmt);
break;
}
case Intrinsic::uadd_sat:
case Intrinsic::usub_sat: {
bool IsAdd = II->getIntrinsicID() == Intrinsic::uadd_sat;
computeKnownBits(I->getOperand(0), Known, Depth + 1, Q);
computeKnownBits(I->getOperand(1), Known2, Depth + 1, Q);

// Add: Leading ones of either operand are preserved.
// Sub: Leading zeros of LHS and leading ones of RHS are preserved
// as leading zeros in the result.
unsigned LeadingKnown;
if (IsAdd)
LeadingKnown = std::max(Known.countMinLeadingOnes(),
Known2.countMinLeadingOnes());
else
LeadingKnown = std::max(Known.countMinLeadingZeros(),
Known2.countMinLeadingOnes());

Known = KnownBits::computeForAddSub(
IsAdd, /* NSW */ false, Known, Known2);

// We select between the operation result and all-ones/zero
// respectively, so we can preserve known ones/zeros.
if (IsAdd) {
Known.One.setHighBits(LeadingKnown);
Known.Zero.clearAllBits();
} else {
Known.Zero.setHighBits(LeadingKnown);
Known.One.clearAllBits();
}
break;
}
case Intrinsic::x86_sse42_crc32_64_64:
Known.Zero.setBitsFrom(32);
break;
Expand Down
71 changes: 71 additions & 0 deletions llvm/unittests/Analysis/ValueTrackingTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -615,3 +615,74 @@ TEST_F(ComputeKnownBitsTest, ComputeKnownFshlZero) {
"declare i16 @llvm.fshl.i16(i16, i16, i16)\n");
expectKnownBits(/*zero*/ 15u, /*one*/ 3840u);
}

TEST_F(ComputeKnownBitsTest, ComputeKnownUAddSatLeadingOnes) {
// uadd.sat(1111...1, ........)
// = 1111....
parseAssembly(
"define i8 @test(i8 %a, i8 %b) {\n"
" %aa = or i8 %a, 241\n"
" %A = call i8 @llvm.uadd.sat.i8(i8 %aa, i8 %b)\n"
" ret i8 %A\n"
"}\n"
"declare i8 @llvm.uadd.sat.i8(i8, i8)\n");
expectKnownBits(/*zero*/ 0u, /*one*/ 240u);
}

TEST_F(ComputeKnownBitsTest, ComputeKnownUAddSatOnesPreserved) {
// uadd.sat(00...011, .1...110)
// = .......1
parseAssembly(
"define i8 @test(i8 %a, i8 %b) {\n"
" %aa = or i8 %a, 3\n"
" %aaa = and i8 %aa, 59\n"
" %bb = or i8 %b, 70\n"
" %bbb = and i8 %bb, 254\n"
" %A = call i8 @llvm.uadd.sat.i8(i8 %aaa, i8 %bbb)\n"
" ret i8 %A\n"
"}\n"
"declare i8 @llvm.uadd.sat.i8(i8, i8)\n");
expectKnownBits(/*zero*/ 0u, /*one*/ 1u);
}

TEST_F(ComputeKnownBitsTest, ComputeKnownUSubSatLHSLeadingZeros) {
// usub.sat(0000...0, ........)
// = 0000....
parseAssembly(
"define i8 @test(i8 %a, i8 %b) {\n"
" %aa = and i8 %a, 14\n"
" %A = call i8 @llvm.usub.sat.i8(i8 %aa, i8 %b)\n"
" ret i8 %A\n"
"}\n"
"declare i8 @llvm.usub.sat.i8(i8, i8)\n");
expectKnownBits(/*zero*/ 240u, /*one*/ 0u);
}

TEST_F(ComputeKnownBitsTest, ComputeKnownUSubSatRHSLeadingOnes) {
// usub.sat(........, 1111...1)
// = 0000....
parseAssembly(
"define i8 @test(i8 %a, i8 %b) {\n"
" %bb = or i8 %a, 241\n"
" %A = call i8 @llvm.usub.sat.i8(i8 %a, i8 %bb)\n"
" ret i8 %A\n"
"}\n"
"declare i8 @llvm.usub.sat.i8(i8, i8)\n");
expectKnownBits(/*zero*/ 240u, /*one*/ 0u);
}

TEST_F(ComputeKnownBitsTest, ComputeKnownUSubSatZerosPreserved) {
// usub.sat(11...011, .1...110)
// = ......0.
parseAssembly(
"define i8 @test(i8 %a, i8 %b) {\n"
" %aa = or i8 %a, 195\n"
" %aaa = and i8 %aa, 251\n"
" %bb = or i8 %b, 70\n"
" %bbb = and i8 %bb, 254\n"
" %A = call i8 @llvm.usub.sat.i8(i8 %aaa, i8 %bbb)\n"
" ret i8 %A\n"
"}\n"
"declare i8 @llvm.usub.sat.i8(i8, i8)\n");
expectKnownBits(/*zero*/ 2u, /*one*/ 0u);
}

0 comments on commit ed3ca92

Please sign in to comment.