Skip to content

Commit 188f9a3

Browse files
committed
[Attributor] AAValueConstantRange: Value range analysis using constant 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
1 parent b891490 commit 188f9a3

File tree

9 files changed

+1514
-39
lines changed

9 files changed

+1514
-39
lines changed

llvm/include/llvm/Transforms/IPO/Attributor.h

Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@
105105
#include "llvm/Analysis/MustExecute.h"
106106
#include "llvm/Analysis/TargetLibraryInfo.h"
107107
#include "llvm/IR/CallSite.h"
108+
#include "llvm/IR/ConstantRange.h"
108109
#include "llvm/IR/PassManager.h"
109110

110111
namespace llvm {
@@ -1503,6 +1504,116 @@ struct BooleanState : public IntegerStateBase<bool, 1, 0> {
15031504
}
15041505
};
15051506

1507+
/// State for an integer range.
1508+
struct IntegerRangeState : public AbstractState {
1509+
1510+
/// Bitwidth of the associated value.
1511+
uint32_t BitWidth;
1512+
1513+
/// State representing assumed range, initially set to empty.
1514+
ConstantRange Assumed;
1515+
1516+
/// State representing known range, initially set to [-inf, inf].
1517+
ConstantRange Known;
1518+
1519+
IntegerRangeState(uint32_t BitWidth)
1520+
: BitWidth(BitWidth), Assumed(ConstantRange::getEmpty(BitWidth)),
1521+
Known(ConstantRange::getFull(BitWidth)) {}
1522+
1523+
/// Return the worst possible representable state.
1524+
static ConstantRange getWorstState(uint32_t BitWidth) {
1525+
return ConstantRange::getFull(BitWidth);
1526+
}
1527+
1528+
/// Return the best possible representable state.
1529+
static ConstantRange getBestState(uint32_t BitWidth) {
1530+
return ConstantRange::getEmpty(BitWidth);
1531+
}
1532+
1533+
/// Return associated values' bit width.
1534+
uint32_t getBitWidth() const { return BitWidth; }
1535+
1536+
/// See AbstractState::isValidState()
1537+
bool isValidState() const override {
1538+
return BitWidth > 0 && !Assumed.isFullSet();
1539+
}
1540+
1541+
/// See AbstractState::isAtFixpoint()
1542+
bool isAtFixpoint() const override { return Assumed == Known; }
1543+
1544+
/// See AbstractState::indicateOptimisticFixpoint(...)
1545+
ChangeStatus indicateOptimisticFixpoint() override {
1546+
Known = Assumed;
1547+
return ChangeStatus::CHANGED;
1548+
}
1549+
1550+
/// See AbstractState::indicatePessimisticFixpoint(...)
1551+
ChangeStatus indicatePessimisticFixpoint() override {
1552+
Assumed = Known;
1553+
return ChangeStatus::CHANGED;
1554+
}
1555+
1556+
/// Return the known state encoding
1557+
ConstantRange getKnown() const { return Known; }
1558+
1559+
/// Return the assumed state encoding.
1560+
ConstantRange getAssumed() const { return Assumed; }
1561+
1562+
/// Unite assumed range with the passed state.
1563+
void unionAssumed(const ConstantRange &R) {
1564+
// Don't loose a known range.
1565+
Assumed = Assumed.unionWith(R).intersectWith(Known);
1566+
}
1567+
1568+
/// See IntegerRangeState::unionAssumed(..).
1569+
void unionAssumed(const IntegerRangeState &R) {
1570+
unionAssumed(R.getAssumed());
1571+
}
1572+
1573+
/// Unite known range with the passed state.
1574+
void unionKnown(const ConstantRange &R) {
1575+
// Don't loose a known range.
1576+
Known = Known.unionWith(R);
1577+
Assumed = Assumed.unionWith(Known);
1578+
}
1579+
1580+
/// See IntegerRangeState::unionKnown(..).
1581+
void unionKnown(const IntegerRangeState &R) { unionKnown(R.getKnown()); }
1582+
1583+
/// Intersect known range with the passed state.
1584+
void intersectKnown(const ConstantRange &R) {
1585+
Assumed = Assumed.intersectWith(R);
1586+
Known = Known.intersectWith(R);
1587+
}
1588+
1589+
/// See IntegerRangeState::intersectKnown(..).
1590+
void intersectKnown(const IntegerRangeState &R) {
1591+
intersectKnown(R.getKnown());
1592+
}
1593+
1594+
/// Equality for IntegerRangeState.
1595+
bool operator==(const IntegerRangeState &R) const {
1596+
return getAssumed() == R.getAssumed() && getKnown() == R.getKnown();
1597+
}
1598+
1599+
/// "Clamp" this state with \p R. The result is subtype dependent but it is
1600+
/// intended that only information assumed in both states will be assumed in
1601+
/// this one afterwards.
1602+
IntegerRangeState operator^=(const IntegerRangeState &R) {
1603+
// NOTE: `^=` operator seems like `intersect` but in this case, we need to
1604+
// take `union`.
1605+
unionAssumed(R);
1606+
return *this;
1607+
}
1608+
1609+
IntegerRangeState operator&=(const IntegerRangeState &R) {
1610+
// NOTE: `&=` operator seems like `intersect` but in this case, we need to
1611+
// take `union`.
1612+
unionKnown(R);
1613+
unionAssumed(R);
1614+
return *this;
1615+
}
1616+
};
15061617
/// Helper struct necessary as the modular build fails if the virtual method
15071618
/// IRAttribute::manifest is defined in the Attributor.cpp.
15081619
struct IRAttributeManifest {
@@ -1696,6 +1807,7 @@ template <typename base_ty, base_ty BestState, base_ty WorstState>
16961807
raw_ostream &
16971808
operator<<(raw_ostream &OS,
16981809
const IntegerStateBase<base_ty, BestState, WorstState> &State);
1810+
raw_ostream &operator<<(raw_ostream &OS, const IntegerRangeState &State);
16991811
///}
17001812

17011813
struct AttributorPass : public PassInfoMixin<AttributorPass> {
@@ -2331,6 +2443,55 @@ struct AAMemoryBehavior
23312443
static const char ID;
23322444
};
23332445

2446+
/// An abstract interface for range value analysis.
2447+
struct AAValueConstantRange : public IntegerRangeState,
2448+
public AbstractAttribute,
2449+
public IRPosition {
2450+
AAValueConstantRange(const IRPosition &IRP)
2451+
: IntegerRangeState(
2452+
IRP.getAssociatedValue().getType()->getIntegerBitWidth()),
2453+
IRPosition(IRP) {}
2454+
2455+
/// Return an IR position, see struct IRPosition.
2456+
const IRPosition &getIRPosition() const override { return *this; }
2457+
2458+
/// See AbstractAttribute::getState(...).
2459+
IntegerRangeState &getState() override { return *this; }
2460+
const AbstractState &getState() const override { return *this; }
2461+
2462+
/// Create an abstract attribute view for the position \p IRP.
2463+
static AAValueConstantRange &createForPosition(const IRPosition &IRP,
2464+
Attributor &A);
2465+
2466+
/// Return an assumed range for the assocaited value a program point \p CtxI.
2467+
/// If \p I is nullptr, simply return an assumed range.
2468+
virtual ConstantRange
2469+
getAssumedConstantRange(Attributor &A,
2470+
const Instruction *CtxI = nullptr) const = 0;
2471+
2472+
/// Return a known range for the assocaited value at a program point \p CtxI.
2473+
/// If \p I is nullptr, simply return a known range.
2474+
virtual ConstantRange
2475+
getKnownConstantRange(Attributor &A,
2476+
const Instruction *CtxI = nullptr) const = 0;
2477+
2478+
/// Return an assumed constant for the assocaited value a program point \p
2479+
/// CtxI.
2480+
Optional<ConstantInt *>
2481+
getAssumedConstantInt(Attributor &A, const Instruction *CtxI = nullptr) const {
2482+
ConstantRange RangeV = getAssumedConstantRange(A, CtxI);
2483+
if (auto *C = RangeV.getSingleElement())
2484+
return cast<ConstantInt>(
2485+
ConstantInt::get(getAssociatedValue().getType(), *C));
2486+
if (RangeV.isEmptySet())
2487+
return llvm::None;
2488+
return nullptr;
2489+
}
2490+
2491+
/// Unique ID (due to the unique address)
2492+
static const char ID;
2493+
};
2494+
23342495
} // end namespace llvm
23352496

23362497
#endif // LLVM_TRANSFORMS_IPO_FUNCTIONATTRS_H

0 commit comments

Comments
 (0)