-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[InstCombine] Create a class to lazily track computed known bits #66611
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
9e6f0e2
a736647
edb53d4
85b77d9
75eae19
3e13887
c72d7a5
15b683a
cb53056
a6c2f9a
aa399bb
5347ffd
1989d10
3675719
ec7c5ee
716f1fa
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
//===- llvm/Analysis/WithCache.h - KnownBits cache for pointers -*- C++ -*-===// | ||
// | ||
// 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 | ||
// | ||
//===----------------------------------------------------------------------===// | ||
// | ||
// Store a pointer to any type along with the KnownBits information for it | ||
// that is computed lazily (if required). | ||
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
#ifndef LLVM_ANALYSIS_WITHCACHE_H | ||
#define LLVM_ANALYSIS_WITHCACHE_H | ||
|
||
#include "llvm/IR/Value.h" | ||
#include "llvm/Support/KnownBits.h" | ||
#include <type_traits> | ||
|
||
namespace llvm { | ||
struct SimplifyQuery; | ||
KnownBits computeKnownBits(const Value *V, unsigned Depth, | ||
const SimplifyQuery &Q); | ||
|
||
template <typename Arg> class WithCache { | ||
static_assert(std::is_pointer_v<Arg>, "WithCache requires a pointer type!"); | ||
|
||
using UnderlyingType = std::remove_pointer_t<Arg>; | ||
constexpr static bool IsConst = std::is_const_v<Arg>; | ||
|
||
template <typename T, bool Const> | ||
using conditionally_const_t = std::conditional_t<Const, const T, T>; | ||
|
||
using PointerType = conditionally_const_t<UnderlyingType *, IsConst>; | ||
using ReferenceType = conditionally_const_t<UnderlyingType &, IsConst>; | ||
|
||
// Store the presence of the KnownBits information in one of the bits of | ||
// Pointer. | ||
// true -> present | ||
// false -> absent | ||
mutable PointerIntPair<PointerType, 1, bool> Pointer; | ||
mutable KnownBits Known; | ||
|
||
void calculateKnownBits(const SimplifyQuery &Q) const { | ||
Known = computeKnownBits(Pointer.getPointer(), 0, Q); | ||
Pointer.setInt(true); | ||
} | ||
|
||
public: | ||
WithCache(PointerType Pointer) : Pointer(Pointer, false) {} | ||
WithCache(PointerType Pointer, const KnownBits &Known) | ||
: Pointer(Pointer, true), Known(Known) {} | ||
|
||
[[nodiscard]] PointerType getValue() const { return Pointer.getPointer(); } | ||
|
||
[[nodiscard]] const KnownBits &getKnownBits(const SimplifyQuery &Q) const { | ||
if (!hasKnownBits()) | ||
calculateKnownBits(Q); | ||
return Known; | ||
} | ||
|
||
[[nodiscard]] bool hasKnownBits() const { return Pointer.getInt(); } | ||
|
||
operator PointerType() const { return Pointer.getPointer(); } | ||
PointerType operator->() const { return Pointer.getPointer(); } | ||
ReferenceType operator*() const { return *Pointer.getPointer(); } | ||
}; | ||
} // namespace llvm | ||
|
||
#endif |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -33,6 +33,7 @@ | |
#include "llvm/Analysis/OptimizationRemarkEmitter.h" | ||
#include "llvm/Analysis/TargetLibraryInfo.h" | ||
#include "llvm/Analysis/VectorUtils.h" | ||
#include "llvm/Analysis/WithCache.h" | ||
#include "llvm/IR/Argument.h" | ||
#include "llvm/IR/Attributes.h" | ||
#include "llvm/IR/BasicBlock.h" | ||
|
@@ -178,31 +179,29 @@ void llvm::computeKnownBits(const Value *V, const APInt &DemandedElts, | |
SimplifyQuery(DL, DT, AC, safeCxtI(V, CxtI), UseInstrInfo)); | ||
} | ||
|
||
static KnownBits computeKnownBits(const Value *V, const APInt &DemandedElts, | ||
unsigned Depth, const SimplifyQuery &Q); | ||
|
||
static KnownBits computeKnownBits(const Value *V, unsigned Depth, | ||
const SimplifyQuery &Q); | ||
|
||
KnownBits llvm::computeKnownBits(const Value *V, const DataLayout &DL, | ||
unsigned Depth, AssumptionCache *AC, | ||
const Instruction *CxtI, | ||
const DominatorTree *DT, bool UseInstrInfo) { | ||
return ::computeKnownBits( | ||
return computeKnownBits( | ||
V, Depth, SimplifyQuery(DL, DT, AC, safeCxtI(V, CxtI), UseInstrInfo)); | ||
} | ||
|
||
KnownBits llvm::computeKnownBits(const Value *V, const APInt &DemandedElts, | ||
const DataLayout &DL, unsigned Depth, | ||
AssumptionCache *AC, const Instruction *CxtI, | ||
const DominatorTree *DT, bool UseInstrInfo) { | ||
return ::computeKnownBits( | ||
return computeKnownBits( | ||
V, DemandedElts, Depth, | ||
SimplifyQuery(DL, DT, AC, safeCxtI(V, CxtI), UseInstrInfo)); | ||
} | ||
|
||
bool llvm::haveNoCommonBitsSet(const Value *LHS, const Value *RHS, | ||
bool llvm::haveNoCommonBitsSet(const WithCache<const Value *> &LHSCache, | ||
const WithCache<const Value *> &RHSCache, | ||
const SimplifyQuery &SQ) { | ||
const Value *LHS = LHSCache.getValue(); | ||
const Value *RHS = RHSCache.getValue(); | ||
|
||
assert(LHS->getType() == RHS->getType() && | ||
"LHS and RHS should have the same type"); | ||
assert(LHS->getType()->isIntOrIntVectorTy() && | ||
|
@@ -250,12 +249,9 @@ bool llvm::haveNoCommonBitsSet(const Value *LHS, const Value *RHS, | |
match(LHS, m_Not(m_c_Or(m_Specific(A), m_Specific(B))))) | ||
return true; | ||
} | ||
IntegerType *IT = cast<IntegerType>(LHS->getType()->getScalarType()); | ||
KnownBits LHSKnown(IT->getBitWidth()); | ||
KnownBits RHSKnown(IT->getBitWidth()); | ||
::computeKnownBits(LHS, LHSKnown, 0, SQ); | ||
::computeKnownBits(RHS, RHSKnown, 0, SQ); | ||
return KnownBits::haveNoCommonBitsSet(LHSKnown, RHSKnown); | ||
|
||
return KnownBits::haveNoCommonBitsSet(LHSCache.getKnownBits(SQ), | ||
RHSCache.getKnownBits(SQ)); | ||
} | ||
|
||
bool llvm::isOnlyUsedInZeroEqualityComparison(const Instruction *I) { | ||
|
@@ -1784,19 +1780,19 @@ static void computeKnownBitsFromOperator(const Operator *I, | |
|
||
/// Determine which bits of V are known to be either zero or one and return | ||
/// them. | ||
KnownBits computeKnownBits(const Value *V, const APInt &DemandedElts, | ||
unsigned Depth, const SimplifyQuery &Q) { | ||
KnownBits llvm::computeKnownBits(const Value *V, const APInt &DemandedElts, | ||
unsigned Depth, const SimplifyQuery &Q) { | ||
KnownBits Known(getBitWidth(V->getType(), Q.DL)); | ||
computeKnownBits(V, DemandedElts, Known, Depth, Q); | ||
::computeKnownBits(V, DemandedElts, Known, Depth, Q); | ||
return Known; | ||
} | ||
|
||
/// Determine which bits of V are known to be either zero or one and return | ||
/// them. | ||
KnownBits computeKnownBits(const Value *V, unsigned Depth, | ||
const SimplifyQuery &Q) { | ||
KnownBits llvm::computeKnownBits(const Value *V, unsigned Depth, | ||
const SimplifyQuery &Q) { | ||
KnownBits Known(getBitWidth(V->getType(), Q.DL)); | ||
computeKnownBits(V, Known, Depth, Q); | ||
::computeKnownBits(V, Known, Depth, Q); | ||
return Known; | ||
} | ||
|
||
|
@@ -6256,10 +6252,11 @@ static OverflowResult mapOverflowResult(ConstantRange::OverflowResult OR) { | |
|
||
/// Combine constant ranges from computeConstantRange() and computeKnownBits(). | ||
static ConstantRange | ||
computeConstantRangeIncludingKnownBits(const Value *V, bool ForSigned, | ||
computeConstantRangeIncludingKnownBits(const WithCache<const Value *> &V, | ||
bool ForSigned, | ||
const SimplifyQuery &SQ) { | ||
KnownBits Known = ::computeKnownBits(V, /*Depth=*/0, SQ); | ||
ConstantRange CR1 = ConstantRange::fromKnownBits(Known, ForSigned); | ||
ConstantRange CR1 = | ||
ConstantRange::fromKnownBits(V.getKnownBits(SQ), ForSigned); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would still personally be in favor of making There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If we add a getConstantRange API on this class, then what it would have to return is a cached version of computeConstantRange(), not ConstantRange::fromKnownBits(). That's something we could evaluate, but not as part of this PR. I don't think it would be worthwhile right now (because, while we do repeated computeConstantRange() calls, they use different signedness, so couldn't be reused). |
||
ConstantRange CR2 = computeConstantRange(V, ForSigned, SQ.IIQ.UseInstrInfo); | ||
ConstantRange::PreferredRangeType RangeType = | ||
ForSigned ? ConstantRange::Signed : ConstantRange::Unsigned; | ||
|
@@ -6269,8 +6266,8 @@ computeConstantRangeIncludingKnownBits(const Value *V, bool ForSigned, | |
OverflowResult llvm::computeOverflowForUnsignedMul(const Value *LHS, | ||
const Value *RHS, | ||
const SimplifyQuery &SQ) { | ||
KnownBits LHSKnown = ::computeKnownBits(LHS, /*Depth=*/0, SQ); | ||
KnownBits RHSKnown = ::computeKnownBits(RHS, /*Depth=*/0, SQ); | ||
KnownBits LHSKnown = computeKnownBits(LHS, /*Depth=*/0, SQ); | ||
KnownBits RHSKnown = computeKnownBits(RHS, /*Depth=*/0, SQ); | ||
ConstantRange LHSRange = ConstantRange::fromKnownBits(LHSKnown, false); | ||
ConstantRange RHSRange = ConstantRange::fromKnownBits(RHSKnown, false); | ||
return mapOverflowResult(LHSRange.unsignedMulMayOverflow(RHSRange)); | ||
|
@@ -6307,28 +6304,29 @@ OverflowResult llvm::computeOverflowForSignedMul(const Value *LHS, | |
// product is exactly the minimum negative number. | ||
// E.g. mul i16 with 17 sign bits: 0xff00 * 0xff80 = 0x8000 | ||
// For simplicity we just check if at least one side is not negative. | ||
KnownBits LHSKnown = ::computeKnownBits(LHS, /*Depth=*/0, SQ); | ||
KnownBits RHSKnown = ::computeKnownBits(RHS, /*Depth=*/0, SQ); | ||
KnownBits LHSKnown = computeKnownBits(LHS, /*Depth=*/0, SQ); | ||
KnownBits RHSKnown = computeKnownBits(RHS, /*Depth=*/0, SQ); | ||
if (LHSKnown.isNonNegative() || RHSKnown.isNonNegative()) | ||
return OverflowResult::NeverOverflows; | ||
} | ||
return OverflowResult::MayOverflow; | ||
} | ||
|
||
OverflowResult llvm::computeOverflowForUnsignedAdd(const Value *LHS, | ||
const Value *RHS, | ||
const SimplifyQuery &SQ) { | ||
OverflowResult | ||
llvm::computeOverflowForUnsignedAdd(const WithCache<const Value *> &LHS, | ||
const WithCache<const Value *> &RHS, | ||
const SimplifyQuery &SQ) { | ||
ConstantRange LHSRange = | ||
computeConstantRangeIncludingKnownBits(LHS, /*ForSigned=*/false, SQ); | ||
ConstantRange RHSRange = | ||
computeConstantRangeIncludingKnownBits(RHS, /*ForSigned=*/false, SQ); | ||
return mapOverflowResult(LHSRange.unsignedAddMayOverflow(RHSRange)); | ||
} | ||
|
||
static OverflowResult computeOverflowForSignedAdd(const Value *LHS, | ||
const Value *RHS, | ||
const AddOperator *Add, | ||
const SimplifyQuery &SQ) { | ||
static OverflowResult | ||
computeOverflowForSignedAdd(const WithCache<const Value *> &LHS, | ||
const WithCache<const Value *> &RHS, | ||
const AddOperator *Add, const SimplifyQuery &SQ) { | ||
if (Add && Add->hasNoSignedWrap()) { | ||
return OverflowResult::NeverOverflows; | ||
} | ||
|
@@ -6944,9 +6942,10 @@ OverflowResult llvm::computeOverflowForSignedAdd(const AddOperator *Add, | |
Add, SQ); | ||
} | ||
|
||
OverflowResult llvm::computeOverflowForSignedAdd(const Value *LHS, | ||
const Value *RHS, | ||
const SimplifyQuery &SQ) { | ||
OverflowResult | ||
llvm::computeOverflowForSignedAdd(const WithCache<const Value *> &LHS, | ||
const WithCache<const Value *> &RHS, | ||
const SimplifyQuery &SQ) { | ||
return ::computeOverflowForSignedAdd(LHS, RHS, nullptr, SQ); | ||
} | ||
|
||
|
Uh oh!
There was an error while loading. Please reload this page.