summaryrefslogtreecommitdiffstats
path: root/llvm/unittests/Support/KnownBitsTest.cpp
diff options
context:
space:
mode:
authorNikita Popov <nikita.ppv@gmail.com>2019-04-12 18:18:08 +0000
committerNikita Popov <nikita.ppv@gmail.com>2019-04-12 18:18:08 +0000
commit7671fc71f62a7387c06742c569fe17608796e8f2 (patch)
treec219b1b1ed382fe7fe62a2470cbbffe205b89b9a /llvm/unittests/Support/KnownBitsTest.cpp
parent7a60cd38af5563ebe4efa6f1544dca5a5ebebbee (diff)
downloadbcm5719-llvm-7671fc71f62a7387c06742c569fe17608796e8f2.tar.gz
bcm5719-llvm-7671fc71f62a7387c06742c569fe17608796e8f2.zip
[KnownBits] Add computeForAddCarry()
This is for D60460. computeForAddSub() essentially already supports carries because it has to deal with subtractions. This revision extracts a lower-level computeForAddCarry() function, which allows computing the known bits for add (carry known zero), sub (carry known one) and addcarry (carry unknown). As we don't seem to have any yet, I've added a unit test file for KnownBits and exhaustive tests for the new computeForAddCarry() functionality, as well the existing computeForAddSub() function. Differential Revision: https://reviews.llvm.org/D60522 llvm-svn: 358297
Diffstat (limited to 'llvm/unittests/Support/KnownBitsTest.cpp')
-rw-r--r--llvm/unittests/Support/KnownBitsTest.cpp130
1 files changed, 130 insertions, 0 deletions
diff --git a/llvm/unittests/Support/KnownBitsTest.cpp b/llvm/unittests/Support/KnownBitsTest.cpp
new file mode 100644
index 00000000000..c2b3b127cf1
--- /dev/null
+++ b/llvm/unittests/Support/KnownBitsTest.cpp
@@ -0,0 +1,130 @@
+//===- llvm/unittest/Support/KnownBitsTest.cpp - KnownBits tests ----------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements unit tests for KnownBits functions.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/KnownBits.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+
+namespace {
+
+template<typename FnTy>
+void ForeachKnownBits(unsigned Bits, FnTy Fn) {
+ unsigned Max = 1 << Bits;
+ KnownBits Known(Bits);
+ for (unsigned Zero = 0; Zero < Max; ++Zero) {
+ for (unsigned One = 0; One < Max; ++One) {
+ Known.Zero = Zero;
+ Known.One = One;
+ if (Known.hasConflict())
+ continue;
+
+ Fn(Known);
+ }
+ }
+}
+
+template<typename FnTy>
+void ForeachNumInKnownBits(const KnownBits &Known, FnTy Fn) {
+ unsigned Bits = Known.getBitWidth();
+ unsigned Max = 1 << Bits;
+ for (unsigned N = 0; N < Max; ++N) {
+ APInt Num(Bits, N);
+ if ((Num & Known.Zero) != 0 || (~Num & Known.One) != 0)
+ continue;
+
+ Fn(Num);
+ }
+}
+
+TEST(KnownBitsTest, AddCarryExhaustive) {
+ unsigned Bits = 4;
+ ForeachKnownBits(Bits, [&](const KnownBits &Known1) {
+ ForeachKnownBits(Bits, [&](const KnownBits &Known2) {
+ ForeachKnownBits(1, [&](const KnownBits &KnownCarry) {
+ // Explicitly compute known bits of the addition by trying all
+ // possibilities.
+ KnownBits Known(Bits);
+ Known.Zero.setAllBits();
+ Known.One.setAllBits();
+ ForeachNumInKnownBits(Known1, [&](const APInt &N1) {
+ ForeachNumInKnownBits(Known2, [&](const APInt &N2) {
+ ForeachNumInKnownBits(KnownCarry, [&](const APInt &Carry) {
+ APInt Add = N1 + N2;
+ if (Carry.getBoolValue())
+ ++Add;
+
+ Known.One &= Add;
+ Known.Zero &= ~Add;
+ });
+ });
+ });
+
+ KnownBits KnownComputed = KnownBits::computeForAddCarry(
+ Known1, Known2, KnownCarry);
+ EXPECT_EQ(Known.Zero, KnownComputed.Zero);
+ EXPECT_EQ(Known.One, KnownComputed.One);
+ });
+ });
+ });
+}
+
+static void TestAddSubExhaustive(bool IsAdd) {
+ unsigned Bits = 4;
+ ForeachKnownBits(Bits, [&](const KnownBits &Known1) {
+ ForeachKnownBits(Bits, [&](const KnownBits &Known2) {
+ KnownBits Known(Bits), KnownNSW(Bits);
+ Known.Zero.setAllBits();
+ Known.One.setAllBits();
+ KnownNSW.Zero.setAllBits();
+ KnownNSW.One.setAllBits();
+
+ ForeachNumInKnownBits(Known1, [&](const APInt &N1) {
+ ForeachNumInKnownBits(Known2, [&](const APInt &N2) {
+ bool Overflow;
+ APInt Res;
+ if (IsAdd)
+ Res = N1.sadd_ov(N2, Overflow);
+ else
+ Res = N1.ssub_ov(N2, Overflow);
+
+ Known.One &= Res;
+ Known.Zero &= ~Res;
+
+ if (!Overflow) {
+ KnownNSW.One &= Res;
+ KnownNSW.Zero &= ~Res;
+ }
+ });
+ });
+
+ KnownBits KnownComputed = KnownBits::computeForAddSub(
+ IsAdd, /*NSW*/false, Known1, Known2);
+ EXPECT_EQ(Known.Zero, KnownComputed.Zero);
+ EXPECT_EQ(Known.One, KnownComputed.One);
+
+ // The NSW calculation is not precise, only check that it's
+ // conservatively correct.
+ KnownBits KnownNSWComputed = KnownBits::computeForAddSub(
+ IsAdd, /*NSW*/true, Known1, Known2);
+ EXPECT_TRUE(KnownNSWComputed.Zero.isSubsetOf(KnownNSW.Zero));
+ EXPECT_TRUE(KnownNSWComputed.One.isSubsetOf(KnownNSW.One));
+ });
+ });
+}
+
+TEST(KnownBitsTest, AddSubExhaustive) {
+ TestAddSubExhaustive(true);
+ TestAddSubExhaustive(false);
+}
+
+} // end anonymous namespace
OpenPOWER on IntegriCloud