Skip to content

Commit ed3ca92

Browse files
committed
[ValueTracking] Known bits support for unsigned saturating add/sub
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
1 parent cf0a978 commit ed3ca92

File tree

2 files changed

+102
-0
lines changed

2 files changed

+102
-0
lines changed

llvm/lib/Analysis/ValueTracking.cpp

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1523,6 +1523,37 @@ static void computeKnownBitsFromOperator(const Operator *I, KnownBits &Known,
15231523
Known2.One.shl(ShiftAmt) | Known3.One.lshr(BitWidth - ShiftAmt);
15241524
break;
15251525
}
1526+
case Intrinsic::uadd_sat:
1527+
case Intrinsic::usub_sat: {
1528+
bool IsAdd = II->getIntrinsicID() == Intrinsic::uadd_sat;
1529+
computeKnownBits(I->getOperand(0), Known, Depth + 1, Q);
1530+
computeKnownBits(I->getOperand(1), Known2, Depth + 1, Q);
1531+
1532+
// Add: Leading ones of either operand are preserved.
1533+
// Sub: Leading zeros of LHS and leading ones of RHS are preserved
1534+
// as leading zeros in the result.
1535+
unsigned LeadingKnown;
1536+
if (IsAdd)
1537+
LeadingKnown = std::max(Known.countMinLeadingOnes(),
1538+
Known2.countMinLeadingOnes());
1539+
else
1540+
LeadingKnown = std::max(Known.countMinLeadingZeros(),
1541+
Known2.countMinLeadingOnes());
1542+
1543+
Known = KnownBits::computeForAddSub(
1544+
IsAdd, /* NSW */ false, Known, Known2);
1545+
1546+
// We select between the operation result and all-ones/zero
1547+
// respectively, so we can preserve known ones/zeros.
1548+
if (IsAdd) {
1549+
Known.One.setHighBits(LeadingKnown);
1550+
Known.Zero.clearAllBits();
1551+
} else {
1552+
Known.Zero.setHighBits(LeadingKnown);
1553+
Known.One.clearAllBits();
1554+
}
1555+
break;
1556+
}
15261557
case Intrinsic::x86_sse42_crc32_64_64:
15271558
Known.Zero.setBitsFrom(32);
15281559
break;

llvm/unittests/Analysis/ValueTrackingTest.cpp

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -615,3 +615,74 @@ TEST_F(ComputeKnownBitsTest, ComputeKnownFshlZero) {
615615
"declare i16 @llvm.fshl.i16(i16, i16, i16)\n");
616616
expectKnownBits(/*zero*/ 15u, /*one*/ 3840u);
617617
}
618+
619+
TEST_F(ComputeKnownBitsTest, ComputeKnownUAddSatLeadingOnes) {
620+
// uadd.sat(1111...1, ........)
621+
// = 1111....
622+
parseAssembly(
623+
"define i8 @test(i8 %a, i8 %b) {\n"
624+
" %aa = or i8 %a, 241\n"
625+
" %A = call i8 @llvm.uadd.sat.i8(i8 %aa, i8 %b)\n"
626+
" ret i8 %A\n"
627+
"}\n"
628+
"declare i8 @llvm.uadd.sat.i8(i8, i8)\n");
629+
expectKnownBits(/*zero*/ 0u, /*one*/ 240u);
630+
}
631+
632+
TEST_F(ComputeKnownBitsTest, ComputeKnownUAddSatOnesPreserved) {
633+
// uadd.sat(00...011, .1...110)
634+
// = .......1
635+
parseAssembly(
636+
"define i8 @test(i8 %a, i8 %b) {\n"
637+
" %aa = or i8 %a, 3\n"
638+
" %aaa = and i8 %aa, 59\n"
639+
" %bb = or i8 %b, 70\n"
640+
" %bbb = and i8 %bb, 254\n"
641+
" %A = call i8 @llvm.uadd.sat.i8(i8 %aaa, i8 %bbb)\n"
642+
" ret i8 %A\n"
643+
"}\n"
644+
"declare i8 @llvm.uadd.sat.i8(i8, i8)\n");
645+
expectKnownBits(/*zero*/ 0u, /*one*/ 1u);
646+
}
647+
648+
TEST_F(ComputeKnownBitsTest, ComputeKnownUSubSatLHSLeadingZeros) {
649+
// usub.sat(0000...0, ........)
650+
// = 0000....
651+
parseAssembly(
652+
"define i8 @test(i8 %a, i8 %b) {\n"
653+
" %aa = and i8 %a, 14\n"
654+
" %A = call i8 @llvm.usub.sat.i8(i8 %aa, i8 %b)\n"
655+
" ret i8 %A\n"
656+
"}\n"
657+
"declare i8 @llvm.usub.sat.i8(i8, i8)\n");
658+
expectKnownBits(/*zero*/ 240u, /*one*/ 0u);
659+
}
660+
661+
TEST_F(ComputeKnownBitsTest, ComputeKnownUSubSatRHSLeadingOnes) {
662+
// usub.sat(........, 1111...1)
663+
// = 0000....
664+
parseAssembly(
665+
"define i8 @test(i8 %a, i8 %b) {\n"
666+
" %bb = or i8 %a, 241\n"
667+
" %A = call i8 @llvm.usub.sat.i8(i8 %a, i8 %bb)\n"
668+
" ret i8 %A\n"
669+
"}\n"
670+
"declare i8 @llvm.usub.sat.i8(i8, i8)\n");
671+
expectKnownBits(/*zero*/ 240u, /*one*/ 0u);
672+
}
673+
674+
TEST_F(ComputeKnownBitsTest, ComputeKnownUSubSatZerosPreserved) {
675+
// usub.sat(11...011, .1...110)
676+
// = ......0.
677+
parseAssembly(
678+
"define i8 @test(i8 %a, i8 %b) {\n"
679+
" %aa = or i8 %a, 195\n"
680+
" %aaa = and i8 %aa, 251\n"
681+
" %bb = or i8 %b, 70\n"
682+
" %bbb = and i8 %bb, 254\n"
683+
" %A = call i8 @llvm.usub.sat.i8(i8 %aaa, i8 %bbb)\n"
684+
" ret i8 %A\n"
685+
"}\n"
686+
"declare i8 @llvm.usub.sat.i8(i8, i8)\n");
687+
expectKnownBits(/*zero*/ 2u, /*one*/ 0u);
688+
}

0 commit comments

Comments
 (0)