1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2025-01-31 20:51:52 +01:00
llvm-mirror/unittests/Support/KnownBitsTest.cpp
Jay Foad 3381408aad [KnownBits] Implement accurate unsigned and signed max and min
Use the new implementation in ValueTracking, SelectionDAG and
GlobalISel.

Differential Revision: https://reviews.llvm.org/D87034
2020-09-07 09:09:01 +01:00

196 lines
6.0 KiB
C++

//===- 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 "KnownBitsTest.h"
#include "gtest/gtest.h"
using namespace llvm;
namespace {
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);
}
TEST(KnownBitsTest, BinaryExhaustive) {
unsigned Bits = 4;
ForeachKnownBits(Bits, [&](const KnownBits &Known1) {
ForeachKnownBits(Bits, [&](const KnownBits &Known2) {
KnownBits KnownAnd(Bits);
KnownAnd.Zero.setAllBits();
KnownAnd.One.setAllBits();
KnownBits KnownOr(KnownAnd);
KnownBits KnownXor(KnownAnd);
KnownBits KnownUMax(KnownAnd);
KnownBits KnownUMin(KnownAnd);
KnownBits KnownSMax(KnownAnd);
KnownBits KnownSMin(KnownAnd);
ForeachNumInKnownBits(Known1, [&](const APInt &N1) {
ForeachNumInKnownBits(Known2, [&](const APInt &N2) {
APInt Res;
Res = N1 & N2;
KnownAnd.One &= Res;
KnownAnd.Zero &= ~Res;
Res = N1 | N2;
KnownOr.One &= Res;
KnownOr.Zero &= ~Res;
Res = N1 ^ N2;
KnownXor.One &= Res;
KnownXor.Zero &= ~Res;
Res = APIntOps::umax(N1, N2);
KnownUMax.One &= Res;
KnownUMax.Zero &= ~Res;
Res = APIntOps::umin(N1, N2);
KnownUMin.One &= Res;
KnownUMin.Zero &= ~Res;
Res = APIntOps::smax(N1, N2);
KnownSMax.One &= Res;
KnownSMax.Zero &= ~Res;
Res = APIntOps::smin(N1, N2);
KnownSMin.One &= Res;
KnownSMin.Zero &= ~Res;
});
});
KnownBits ComputedAnd = Known1 & Known2;
EXPECT_EQ(KnownAnd.Zero, ComputedAnd.Zero);
EXPECT_EQ(KnownAnd.One, ComputedAnd.One);
KnownBits ComputedOr = Known1 | Known2;
EXPECT_EQ(KnownOr.Zero, ComputedOr.Zero);
EXPECT_EQ(KnownOr.One, ComputedOr.One);
KnownBits ComputedXor = Known1 ^ Known2;
EXPECT_EQ(KnownXor.Zero, ComputedXor.Zero);
EXPECT_EQ(KnownXor.One, ComputedXor.One);
KnownBits ComputedUMax = KnownBits::umax(Known1, Known2);
EXPECT_EQ(KnownUMax.Zero, ComputedUMax.Zero);
EXPECT_EQ(KnownUMax.One, ComputedUMax.One);
KnownBits ComputedUMin = KnownBits::umin(Known1, Known2);
EXPECT_EQ(KnownUMin.Zero, ComputedUMin.Zero);
EXPECT_EQ(KnownUMin.One, ComputedUMin.One);
KnownBits ComputedSMax = KnownBits::smax(Known1, Known2);
EXPECT_EQ(KnownSMax.Zero, ComputedSMax.Zero);
EXPECT_EQ(KnownSMax.One, ComputedSMax.One);
KnownBits ComputedSMin = KnownBits::smin(Known1, Known2);
EXPECT_EQ(KnownSMin.Zero, ComputedSMin.Zero);
EXPECT_EQ(KnownSMin.One, ComputedSMin.One);
});
});
}
TEST(KnownBitsTest, GetMinMaxVal) {
unsigned Bits = 4;
ForeachKnownBits(Bits, [&](const KnownBits &Known) {
APInt Min = APInt::getMaxValue(Bits);
APInt Max = APInt::getMinValue(Bits);
ForeachNumInKnownBits(Known, [&](const APInt &N) {
Min = APIntOps::umin(Min, N);
Max = APIntOps::umax(Max, N);
});
EXPECT_EQ(Min, Known.getMinValue());
EXPECT_EQ(Max, Known.getMaxValue());
});
}
} // end anonymous namespace