2017-04-26 18:39:58 +02:00
|
|
|
//===- llvm/Support/KnownBits.h - Stores known zeros/ones -------*- C++ -*-===//
|
|
|
|
//
|
2019-01-19 09:50:56 +01:00
|
|
|
// 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
|
2017-04-26 18:39:58 +02:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// This file contains a class for representing known zeros and ones used by
|
|
|
|
// computeKnownBits.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#ifndef LLVM_SUPPORT_KNOWNBITS_H
|
|
|
|
#define LLVM_SUPPORT_KNOWNBITS_H
|
|
|
|
|
|
|
|
#include "llvm/ADT/APInt.h"
|
|
|
|
|
|
|
|
namespace llvm {
|
|
|
|
|
2017-04-29 18:43:11 +02:00
|
|
|
// Struct for tracking the known zeros and ones of a value.
|
2017-04-26 18:39:58 +02:00
|
|
|
struct KnownBits {
|
|
|
|
APInt Zero;
|
|
|
|
APInt One;
|
|
|
|
|
2017-05-04 00:07:25 +02:00
|
|
|
private:
|
2017-08-08 00:35:55 +02:00
|
|
|
// Internal constructor for creating a KnownBits from two APInts.
|
2017-05-04 00:07:25 +02:00
|
|
|
KnownBits(APInt Zero, APInt One)
|
|
|
|
: Zero(std::move(Zero)), One(std::move(One)) {}
|
|
|
|
|
|
|
|
public:
|
2017-04-26 18:39:58 +02:00
|
|
|
// Default construct Zero and One.
|
|
|
|
KnownBits() {}
|
|
|
|
|
|
|
|
/// Create a known bits object of BitWidth bits initialized to unknown.
|
|
|
|
KnownBits(unsigned BitWidth) : Zero(BitWidth, 0), One(BitWidth, 0) {}
|
|
|
|
|
|
|
|
/// Get the bit width of this value.
|
|
|
|
unsigned getBitWidth() const {
|
|
|
|
assert(Zero.getBitWidth() == One.getBitWidth() &&
|
|
|
|
"Zero and One should have the same width!");
|
|
|
|
return Zero.getBitWidth();
|
|
|
|
}
|
2017-04-29 18:43:11 +02:00
|
|
|
|
2017-05-04 01:12:29 +02:00
|
|
|
/// Returns true if there is conflicting information.
|
|
|
|
bool hasConflict() const { return Zero.intersects(One); }
|
|
|
|
|
|
|
|
/// Returns true if we know the value of all bits.
|
|
|
|
bool isConstant() const {
|
|
|
|
assert(!hasConflict() && "KnownBits conflict!");
|
|
|
|
return Zero.countPopulation() + One.countPopulation() == getBitWidth();
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns the value when all bits have a known value. This just returns One
|
|
|
|
/// with a protective assertion.
|
|
|
|
const APInt &getConstant() const {
|
|
|
|
assert(isConstant() && "Can only get value when all bits are known");
|
|
|
|
return One;
|
|
|
|
}
|
|
|
|
|
2017-05-05 19:36:09 +02:00
|
|
|
/// Returns true if we don't know any bits.
|
|
|
|
bool isUnknown() const { return Zero.isNullValue() && One.isNullValue(); }
|
|
|
|
|
|
|
|
/// Resets the known state of all bits.
|
|
|
|
void resetAll() {
|
|
|
|
Zero.clearAllBits();
|
|
|
|
One.clearAllBits();
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns true if value is all zero.
|
|
|
|
bool isZero() const {
|
|
|
|
assert(!hasConflict() && "KnownBits conflict!");
|
|
|
|
return Zero.isAllOnesValue();
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns true if value is all one bits.
|
|
|
|
bool isAllOnes() const {
|
|
|
|
assert(!hasConflict() && "KnownBits conflict!");
|
|
|
|
return One.isAllOnesValue();
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Make all bits known to be zero and discard any previous information.
|
|
|
|
void setAllZero() {
|
|
|
|
Zero.setAllBits();
|
|
|
|
One.clearAllBits();
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Make all bits known to be one and discard any previous information.
|
|
|
|
void setAllOnes() {
|
|
|
|
Zero.clearAllBits();
|
|
|
|
One.setAllBits();
|
|
|
|
}
|
|
|
|
|
2017-04-29 18:43:11 +02:00
|
|
|
/// Returns true if this value is known to be negative.
|
|
|
|
bool isNegative() const { return One.isSignBitSet(); }
|
|
|
|
|
|
|
|
/// Returns true if this value is known to be non-negative.
|
|
|
|
bool isNonNegative() const { return Zero.isSignBitSet(); }
|
|
|
|
|
Fix for AMDGPU MUL_I24 known bits calculation
Summary:
At present, the code calculating known bits of AMDGPU MUL_I24 confuses the concepts of "non-negative number" and "positive number".
In some situations, it results in incorrect code. I have a case where the optimizer replaces the result of calculating MUL_I24(-5, 0) with -8.
Reviewers: foad, arsenm
Reviewed By: arsenm
Subscribers: foad, arsenm, kzhuravl, jvesely, wdng, nhaehnle, yaxunl, dstuttard, tpr, t-tye, hiraditya, llvm-commits
Tags: #llvm
Patch by Eugene Kuznetsov.
Differential Revision: https://reviews.llvm.org/D70367
2019-12-16 11:21:54 +01:00
|
|
|
/// Returns true if this value is known to be positive.
|
|
|
|
bool isStrictlyPositive() const { return Zero.isSignBitSet() && !One.isNullValue(); }
|
|
|
|
|
2017-04-29 18:43:11 +02:00
|
|
|
/// Make this value negative.
|
|
|
|
void makeNegative() {
|
|
|
|
One.setSignBit();
|
|
|
|
}
|
|
|
|
|
2018-07-05 15:51:35 +02:00
|
|
|
/// Make this value non-negative.
|
2017-04-29 18:43:11 +02:00
|
|
|
void makeNonNegative() {
|
|
|
|
Zero.setSignBit();
|
|
|
|
}
|
2017-05-04 00:07:25 +02:00
|
|
|
|
2019-12-03 15:45:47 +01:00
|
|
|
/// Return the minimal value possible given these KnownBits.
|
|
|
|
APInt getMinValue() const {
|
|
|
|
// Assume that all bits that aren't known-ones are zeros.
|
|
|
|
return One;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Return the maximal value possible given these KnownBits.
|
|
|
|
APInt getMaxValue() const {
|
|
|
|
// Assume that all bits that aren't known-zeros are ones.
|
|
|
|
return ~Zero;
|
|
|
|
}
|
|
|
|
|
2020-02-12 14:27:28 +01:00
|
|
|
/// Return known bits for a truncation of the value we're tracking.
|
2019-03-22 20:36:51 +01:00
|
|
|
KnownBits trunc(unsigned BitWidth) const {
|
2017-05-04 00:07:25 +02:00
|
|
|
return KnownBits(Zero.trunc(BitWidth), One.trunc(BitWidth));
|
|
|
|
}
|
|
|
|
|
2020-02-12 14:27:28 +01:00
|
|
|
/// Return known bits for an "any" extension of the value we're tracking,
|
|
|
|
/// where we don't know anything about the extended bits.
|
|
|
|
KnownBits anyext(unsigned BitWidth) const {
|
|
|
|
return KnownBits(Zero.zext(BitWidth), One.zext(BitWidth));
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Return known bits for a zero extension of the value we're tracking.
|
|
|
|
KnownBits zext(unsigned BitWidth) const {
|
2019-02-28 16:45:29 +01:00
|
|
|
unsigned OldBitWidth = getBitWidth();
|
|
|
|
APInt NewZero = Zero.zext(BitWidth);
|
2020-02-12 14:27:28 +01:00
|
|
|
NewZero.setBitsFrom(OldBitWidth);
|
2019-02-28 16:45:29 +01:00
|
|
|
return KnownBits(NewZero, One.zext(BitWidth));
|
2017-05-04 00:07:25 +02:00
|
|
|
}
|
|
|
|
|
2020-02-12 14:27:28 +01:00
|
|
|
/// Return known bits for a sign extension of the value we're tracking.
|
2019-03-22 20:36:51 +01:00
|
|
|
KnownBits sext(unsigned BitWidth) const {
|
2017-05-04 00:07:25 +02:00
|
|
|
return KnownBits(Zero.sext(BitWidth), One.sext(BitWidth));
|
|
|
|
}
|
|
|
|
|
2020-02-12 14:27:28 +01:00
|
|
|
/// Return known bits for an "any" extension or truncation of the value we're
|
|
|
|
/// tracking.
|
|
|
|
KnownBits anyextOrTrunc(unsigned BitWidth) const {
|
|
|
|
if (BitWidth > getBitWidth())
|
|
|
|
return anyext(BitWidth);
|
|
|
|
if (BitWidth < getBitWidth())
|
|
|
|
return trunc(BitWidth);
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Return known bits for a zero extension or truncation of the value we're
|
|
|
|
/// tracking.
|
|
|
|
KnownBits zextOrTrunc(unsigned BitWidth) const {
|
2019-02-28 16:45:29 +01:00
|
|
|
if (BitWidth > getBitWidth())
|
2020-02-12 14:27:28 +01:00
|
|
|
return zext(BitWidth);
|
|
|
|
if (BitWidth < getBitWidth())
|
|
|
|
return trunc(BitWidth);
|
|
|
|
return *this;
|
2017-05-04 00:07:25 +02:00
|
|
|
}
|
2017-05-12 19:20:30 +02:00
|
|
|
|
2020-02-03 16:43:40 +01:00
|
|
|
/// Return a KnownBits with the extracted bits
|
|
|
|
/// [bitPosition,bitPosition+numBits).
|
|
|
|
KnownBits extractBits(unsigned NumBits, unsigned BitPosition) const {
|
|
|
|
return KnownBits(Zero.extractBits(NumBits, BitPosition),
|
|
|
|
One.extractBits(NumBits, BitPosition));
|
|
|
|
}
|
|
|
|
|
2020-09-02 17:01:48 +02:00
|
|
|
/// Return KnownBits based on this, but updated given that the underlying
|
|
|
|
/// value is known to be greater than or equal to Val.
|
|
|
|
KnownBits makeGE(const APInt &Val) const;
|
|
|
|
|
2017-05-12 19:20:30 +02:00
|
|
|
/// Returns the minimum number of trailing zero bits.
|
|
|
|
unsigned countMinTrailingZeros() const {
|
|
|
|
return Zero.countTrailingOnes();
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns the minimum number of trailing one bits.
|
|
|
|
unsigned countMinTrailingOnes() const {
|
|
|
|
return One.countTrailingOnes();
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns the minimum number of leading zero bits.
|
|
|
|
unsigned countMinLeadingZeros() const {
|
|
|
|
return Zero.countLeadingOnes();
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns the minimum number of leading one bits.
|
|
|
|
unsigned countMinLeadingOnes() const {
|
|
|
|
return One.countLeadingOnes();
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns the number of times the sign bit is replicated into the other
|
|
|
|
/// bits.
|
|
|
|
unsigned countMinSignBits() const {
|
|
|
|
if (isNonNegative())
|
|
|
|
return countMinLeadingZeros();
|
|
|
|
if (isNegative())
|
|
|
|
return countMinLeadingOnes();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns the maximum number of trailing zero bits possible.
|
|
|
|
unsigned countMaxTrailingZeros() const {
|
|
|
|
return One.countTrailingZeros();
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns the maximum number of trailing one bits possible.
|
|
|
|
unsigned countMaxTrailingOnes() const {
|
|
|
|
return Zero.countTrailingZeros();
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns the maximum number of leading zero bits possible.
|
|
|
|
unsigned countMaxLeadingZeros() const {
|
|
|
|
return One.countLeadingZeros();
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns the maximum number of leading one bits possible.
|
|
|
|
unsigned countMaxLeadingOnes() const {
|
|
|
|
return Zero.countLeadingZeros();
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns the number of bits known to be one.
|
|
|
|
unsigned countMinPopulation() const {
|
|
|
|
return One.countPopulation();
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns the maximum number of bits that could be one.
|
|
|
|
unsigned countMaxPopulation() const {
|
|
|
|
return getBitWidth() - Zero.countPopulation();
|
|
|
|
}
|
2017-08-08 18:29:35 +02:00
|
|
|
|
2019-04-12 20:18:08 +02:00
|
|
|
/// Compute known bits resulting from adding LHS, RHS and a 1-bit Carry.
|
|
|
|
static KnownBits computeForAddCarry(
|
|
|
|
const KnownBits &LHS, const KnownBits &RHS, const KnownBits &Carry);
|
|
|
|
|
2017-08-08 18:29:35 +02:00
|
|
|
/// Compute known bits resulting from adding LHS and RHS.
|
|
|
|
static KnownBits computeForAddSub(bool Add, bool NSW, const KnownBits &LHS,
|
|
|
|
KnownBits RHS);
|
2020-02-05 17:15:53 +01:00
|
|
|
|
2020-10-06 23:41:31 +02:00
|
|
|
/// Compute known bits resulting from multiplying LHS and RHS.
|
|
|
|
static KnownBits computeForMul(const KnownBits &LHS, const KnownBits &RHS);
|
|
|
|
|
2020-09-02 17:01:48 +02:00
|
|
|
/// Compute known bits for umax(LHS, RHS).
|
|
|
|
static KnownBits umax(const KnownBits &LHS, const KnownBits &RHS);
|
|
|
|
|
|
|
|
/// Compute known bits for umin(LHS, RHS).
|
|
|
|
static KnownBits umin(const KnownBits &LHS, const KnownBits &RHS);
|
|
|
|
|
|
|
|
/// Compute known bits for smax(LHS, RHS).
|
|
|
|
static KnownBits smax(const KnownBits &LHS, const KnownBits &RHS);
|
|
|
|
|
|
|
|
/// Compute known bits for smin(LHS, RHS).
|
|
|
|
static KnownBits smin(const KnownBits &LHS, const KnownBits &RHS);
|
|
|
|
|
2020-08-27 18:15:16 +02:00
|
|
|
/// Insert the bits from a smaller known bits starting at bitPosition.
|
|
|
|
void insertBits(const KnownBits &SubBits, unsigned BitPosition) {
|
|
|
|
Zero.insertBits(SubBits.Zero, BitPosition);
|
|
|
|
One.insertBits(SubBits.One, BitPosition);
|
|
|
|
}
|
|
|
|
|
2020-08-27 22:17:41 +02:00
|
|
|
/// Return a subset of the known bits from [bitPosition,bitPosition+numBits).
|
|
|
|
KnownBits extractBits(unsigned NumBits, unsigned BitPosition) {
|
|
|
|
return KnownBits(Zero.extractBits(NumBits, BitPosition),
|
|
|
|
One.extractBits(NumBits, BitPosition));
|
|
|
|
}
|
|
|
|
|
2020-02-05 17:15:53 +01:00
|
|
|
/// Update known bits based on ANDing with RHS.
|
|
|
|
KnownBits &operator&=(const KnownBits &RHS);
|
|
|
|
|
|
|
|
/// Update known bits based on ORing with RHS.
|
|
|
|
KnownBits &operator|=(const KnownBits &RHS);
|
|
|
|
|
|
|
|
/// Update known bits based on XORing with RHS.
|
|
|
|
KnownBits &operator^=(const KnownBits &RHS);
|
2020-08-27 23:55:35 +02:00
|
|
|
|
2020-09-09 14:22:39 +02:00
|
|
|
/// Compute known bits for the absolute value.
|
|
|
|
KnownBits abs() const;
|
|
|
|
|
2020-08-27 23:55:35 +02:00
|
|
|
KnownBits byteSwap() {
|
|
|
|
return KnownBits(Zero.byteSwap(), One.byteSwap());
|
|
|
|
}
|
|
|
|
|
|
|
|
KnownBits reverseBits() {
|
|
|
|
return KnownBits(Zero.reverseBits(), One.reverseBits());
|
|
|
|
}
|
2017-04-26 18:39:58 +02:00
|
|
|
};
|
|
|
|
|
2020-02-05 17:15:53 +01:00
|
|
|
inline KnownBits operator&(KnownBits LHS, const KnownBits &RHS) {
|
|
|
|
LHS &= RHS;
|
|
|
|
return LHS;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline KnownBits operator&(const KnownBits &LHS, KnownBits &&RHS) {
|
|
|
|
RHS &= LHS;
|
|
|
|
return std::move(RHS);
|
|
|
|
}
|
|
|
|
|
|
|
|
inline KnownBits operator|(KnownBits LHS, const KnownBits &RHS) {
|
|
|
|
LHS |= RHS;
|
|
|
|
return LHS;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline KnownBits operator|(const KnownBits &LHS, KnownBits &&RHS) {
|
|
|
|
RHS |= LHS;
|
|
|
|
return std::move(RHS);
|
|
|
|
}
|
|
|
|
|
|
|
|
inline KnownBits operator^(KnownBits LHS, const KnownBits &RHS) {
|
|
|
|
LHS ^= RHS;
|
|
|
|
return LHS;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline KnownBits operator^(const KnownBits &LHS, KnownBits &&RHS) {
|
|
|
|
RHS ^= LHS;
|
|
|
|
return std::move(RHS);
|
|
|
|
}
|
|
|
|
|
2017-04-26 18:39:58 +02:00
|
|
|
} // end namespace llvm
|
|
|
|
|
|
|
|
#endif
|