llvm-capstone/llvm/unittests/IR/DemandedBitsTest.cpp
Simon Pilgrim c1f6ce0c73 [DemandedBits] Improve accuracy of Add propagator
The current demand propagator for addition will mark all input bits at and right of the alive output bit as alive. But carry won't propagate beyond a bit for which both operands are zero (or one/zero in the case of subtraction) so a more accurate answer is possible given known bits.

I derived a propagator by working through truth tables and using a bit-reversed addition to make demand ripple to the right, but I'm not sure how to make a convincing argument for its correctness in the comments yet. Nevertheless, here's a minimal implementation and test to get feedback.

This would help in a situation where, for example, four bytes (<128) packed into an int are added with four others SIMD-style but only one of the four results is actually read.

Known A:     0_______0_______0_______0_______
Known B:     0_______0_______0_______0_______
AOut:        00000000001000000000000000000000
AB, current: 00000000001111111111111111111111
AB, patch:   00000000001111111000000000000000

Committed on behalf of: @rrika (Erika)

Differential Revision: https://reviews.llvm.org/D72423
2020-08-17 12:54:09 +01:00

67 lines
2.4 KiB
C++

//===- DemandedBitsTest.cpp - DemandedBits 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
//
//===----------------------------------------------------------------------===//
#include "llvm/Analysis/DemandedBits.h"
#include "../Support/KnownBitsTest.h"
#include "llvm/Support/KnownBits.h"
#include "gtest/gtest.h"
using namespace llvm;
namespace {
template <typename Fn1, typename Fn2>
static void TestBinOpExhaustive(Fn1 PropagateFn, Fn2 EvalFn) {
unsigned Bits = 4;
unsigned Max = 1 << Bits;
ForeachKnownBits(Bits, [&](const KnownBits &Known1) {
ForeachKnownBits(Bits, [&](const KnownBits &Known2) {
for (unsigned AOut_ = 0; AOut_ < Max; AOut_++) {
APInt AOut(Bits, AOut_);
APInt AB1 = PropagateFn(0, AOut, Known1, Known2);
APInt AB2 = PropagateFn(1, AOut, Known1, Known2);
{
// If the propagator claims that certain known bits
// didn't matter, check it doesn't change its mind
// when they become unknown.
KnownBits Known1Redacted;
KnownBits Known2Redacted;
Known1Redacted.Zero = Known1.Zero & AB1;
Known1Redacted.One = Known1.One & AB1;
Known2Redacted.Zero = Known2.Zero & AB2;
Known2Redacted.One = Known2.One & AB2;
APInt AB1R = PropagateFn(0, AOut, Known1Redacted, Known2Redacted);
APInt AB2R = PropagateFn(1, AOut, Known1Redacted, Known2Redacted);
EXPECT_EQ(AB1, AB1R);
EXPECT_EQ(AB2, AB2R);
}
ForeachNumInKnownBits(Known1, [&](APInt Value1) {
ForeachNumInKnownBits(Known2, [&](APInt Value2) {
APInt ReferenceResult = EvalFn((Value1 & AB1), (Value2 & AB2));
APInt Result = EvalFn(Value1, Value2);
EXPECT_EQ(Result & AOut, ReferenceResult & AOut);
});
});
}
});
});
}
TEST(DemandedBitsTest, Add) {
TestBinOpExhaustive(DemandedBits::determineLiveOperandBitsAdd,
[](APInt N1, APInt N2) -> APInt { return N1 + N2; });
}
TEST(DemandedBitsTest, Sub) {
TestBinOpExhaustive(DemandedBits::determineLiveOperandBitsSub,
[](APInt N1, APInt N2) -> APInt { return N1 - N2; });
}
} // anonymous namespace