summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNikita Popov <nikita.ppv@gmail.com>2019-03-01 20:07:04 +0000
committerNikita Popov <nikita.ppv@gmail.com>2019-03-01 20:07:04 +0000
commited3ca9272f83e257b49b36f0bc634df2a59c4714 (patch)
treef9fd4a09e7aa1e12a57cc4d56650aa25704cf779
parentcf0a978e1fa182a927af435c2dd3f6862eba14ef (diff)
downloadbcm5719-llvm-ed3ca9272f83e257b49b36f0bc634df2a59c4714.tar.gz
bcm5719-llvm-ed3ca9272f83e257b49b36f0bc634df2a59c4714.zip
[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
-rw-r--r--llvm/lib/Analysis/ValueTracking.cpp31
-rw-r--r--llvm/unittests/Analysis/ValueTrackingTest.cpp71
2 files changed, 102 insertions, 0 deletions
diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index 8b3d16a5125..b4473f857e2 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -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;
diff --git a/llvm/unittests/Analysis/ValueTrackingTest.cpp b/llvm/unittests/Analysis/ValueTrackingTest.cpp
index a0f5aed2b6d..df32287dbff 100644
--- a/llvm/unittests/Analysis/ValueTrackingTest.cpp
+++ b/llvm/unittests/Analysis/ValueTrackingTest.cpp
@@ -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);
+}
OpenPOWER on IntegriCloud