Skip to content

Commit

Permalink
[Attributor] AAValueConstantRange: Value range analysis using constan…
Browse files Browse the repository at this point in the history
…t range

Summary:
This patch introduces `AAValueConstantRange`, which answers a possible range for integer value in a specific program point.
One of the motivations is propagating existing `range` metadata. (I think we need to change the situation that `range` metadata cannot be put to Argument).

The state is a tuple of `ConstantRange` and it is initialized to (known, assumed) = ([-∞, +∞], empty).

Currently, AAValueConstantRange is created in `getAssumedConstant` method when `AAValueSimplify` returns `nullptr`(worst state).

Supported
 - BinaryOperator(add, sub, ...)
 - CmpInst(icmp eq, ...)
 - !range metadata

`AAValueConstantRange` is not intended to extend to polyhedral range value analysis.

Reviewers: jdoerfert, sstefan1

Reviewed By: jdoerfert

Subscribers: phosek, davezarzycki, baziotis, hiraditya, javed.absar, llvm-commits

Tags: #llvm

Differential Revision: https://reviews.llvm.org/D71620
  • Loading branch information
uenoku committed Jan 15, 2020
1 parent b891490 commit 188f9a3
Show file tree
Hide file tree
Showing 9 changed files with 1,514 additions and 39 deletions.
161 changes: 161 additions & 0 deletions llvm/include/llvm/Transforms/IPO/Attributor.h
Expand Up @@ -105,6 +105,7 @@
#include "llvm/Analysis/MustExecute.h"
#include "llvm/Analysis/TargetLibraryInfo.h"
#include "llvm/IR/CallSite.h"
#include "llvm/IR/ConstantRange.h"
#include "llvm/IR/PassManager.h"

namespace llvm {
Expand Down Expand Up @@ -1503,6 +1504,116 @@ struct BooleanState : public IntegerStateBase<bool, 1, 0> {
}
};

/// State for an integer range.
struct IntegerRangeState : public AbstractState {

/// Bitwidth of the associated value.
uint32_t BitWidth;

/// State representing assumed range, initially set to empty.
ConstantRange Assumed;

/// State representing known range, initially set to [-inf, inf].
ConstantRange Known;

IntegerRangeState(uint32_t BitWidth)
: BitWidth(BitWidth), Assumed(ConstantRange::getEmpty(BitWidth)),
Known(ConstantRange::getFull(BitWidth)) {}

/// Return the worst possible representable state.
static ConstantRange getWorstState(uint32_t BitWidth) {
return ConstantRange::getFull(BitWidth);
}

/// Return the best possible representable state.
static ConstantRange getBestState(uint32_t BitWidth) {
return ConstantRange::getEmpty(BitWidth);
}

/// Return associated values' bit width.
uint32_t getBitWidth() const { return BitWidth; }

/// See AbstractState::isValidState()
bool isValidState() const override {
return BitWidth > 0 && !Assumed.isFullSet();
}

/// See AbstractState::isAtFixpoint()
bool isAtFixpoint() const override { return Assumed == Known; }

/// See AbstractState::indicateOptimisticFixpoint(...)
ChangeStatus indicateOptimisticFixpoint() override {
Known = Assumed;
return ChangeStatus::CHANGED;
}

/// See AbstractState::indicatePessimisticFixpoint(...)
ChangeStatus indicatePessimisticFixpoint() override {
Assumed = Known;
return ChangeStatus::CHANGED;
}

/// Return the known state encoding
ConstantRange getKnown() const { return Known; }

/// Return the assumed state encoding.
ConstantRange getAssumed() const { return Assumed; }

/// Unite assumed range with the passed state.
void unionAssumed(const ConstantRange &R) {
// Don't loose a known range.
Assumed = Assumed.unionWith(R).intersectWith(Known);
}

/// See IntegerRangeState::unionAssumed(..).
void unionAssumed(const IntegerRangeState &R) {
unionAssumed(R.getAssumed());
}

/// Unite known range with the passed state.
void unionKnown(const ConstantRange &R) {
// Don't loose a known range.
Known = Known.unionWith(R);
Assumed = Assumed.unionWith(Known);
}

/// See IntegerRangeState::unionKnown(..).
void unionKnown(const IntegerRangeState &R) { unionKnown(R.getKnown()); }

/// Intersect known range with the passed state.
void intersectKnown(const ConstantRange &R) {
Assumed = Assumed.intersectWith(R);
Known = Known.intersectWith(R);
}

/// See IntegerRangeState::intersectKnown(..).
void intersectKnown(const IntegerRangeState &R) {
intersectKnown(R.getKnown());
}

/// Equality for IntegerRangeState.
bool operator==(const IntegerRangeState &R) const {
return getAssumed() == R.getAssumed() && getKnown() == R.getKnown();
}

/// "Clamp" this state with \p R. The result is subtype dependent but it is
/// intended that only information assumed in both states will be assumed in
/// this one afterwards.
IntegerRangeState operator^=(const IntegerRangeState &R) {
// NOTE: `^=` operator seems like `intersect` but in this case, we need to
// take `union`.
unionAssumed(R);
return *this;
}

IntegerRangeState operator&=(const IntegerRangeState &R) {
// NOTE: `&=` operator seems like `intersect` but in this case, we need to
// take `union`.
unionKnown(R);
unionAssumed(R);
return *this;
}
};
/// Helper struct necessary as the modular build fails if the virtual method
/// IRAttribute::manifest is defined in the Attributor.cpp.
struct IRAttributeManifest {
Expand Down Expand Up @@ -1696,6 +1807,7 @@ template <typename base_ty, base_ty BestState, base_ty WorstState>
raw_ostream &
operator<<(raw_ostream &OS,
const IntegerStateBase<base_ty, BestState, WorstState> &State);
raw_ostream &operator<<(raw_ostream &OS, const IntegerRangeState &State);
///}

struct AttributorPass : public PassInfoMixin<AttributorPass> {
Expand Down Expand Up @@ -2331,6 +2443,55 @@ struct AAMemoryBehavior
static const char ID;
};

/// An abstract interface for range value analysis.
struct AAValueConstantRange : public IntegerRangeState,
public AbstractAttribute,
public IRPosition {
AAValueConstantRange(const IRPosition &IRP)
: IntegerRangeState(
IRP.getAssociatedValue().getType()->getIntegerBitWidth()),
IRPosition(IRP) {}

/// Return an IR position, see struct IRPosition.
const IRPosition &getIRPosition() const override { return *this; }

/// See AbstractAttribute::getState(...).
IntegerRangeState &getState() override { return *this; }
const AbstractState &getState() const override { return *this; }

/// Create an abstract attribute view for the position \p IRP.
static AAValueConstantRange &createForPosition(const IRPosition &IRP,
Attributor &A);

/// Return an assumed range for the assocaited value a program point \p CtxI.
/// If \p I is nullptr, simply return an assumed range.
virtual ConstantRange
getAssumedConstantRange(Attributor &A,
const Instruction *CtxI = nullptr) const = 0;

/// Return a known range for the assocaited value at a program point \p CtxI.
/// If \p I is nullptr, simply return a known range.
virtual ConstantRange
getKnownConstantRange(Attributor &A,
const Instruction *CtxI = nullptr) const = 0;

/// Return an assumed constant for the assocaited value a program point \p
/// CtxI.
Optional<ConstantInt *>
getAssumedConstantInt(Attributor &A, const Instruction *CtxI = nullptr) const {
ConstantRange RangeV = getAssumedConstantRange(A, CtxI);
if (auto *C = RangeV.getSingleElement())
return cast<ConstantInt>(
ConstantInt::get(getAssociatedValue().getType(), *C));
if (RangeV.isEmptySet())
return llvm::None;
return nullptr;
}

/// Unique ID (due to the unique address)
static const char ID;
};

} // end namespace llvm

#endif // LLVM_TRANSFORMS_IPO_FUNCTIONATTRS_H

0 comments on commit 188f9a3

Please sign in to comment.