mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-12-13 20:32:21 +00:00
Rewrite instsimplify's handling if icmp on pointer values to remove the
remaining use of AliasAnalysis concepts such as isIdentifiedObject to prove pointer inequality. @external_compare in test/Transforms/InstSimplify/compare.ll shows a simple case where a noalias argument can be equal to a global variable address, and while AliasAnalysis can get away with saying that these pointers don't alias, instsimplify cannot say that they are not equal. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@174122 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
3529d1aa8d
commit
fdd1eafe86
@ -21,10 +21,10 @@
|
||||
#include "llvm/Analysis/InstructionSimplify.h"
|
||||
#include "llvm/ADT/SetVector.h"
|
||||
#include "llvm/ADT/Statistic.h"
|
||||
#include "llvm/Analysis/AliasAnalysis.h"
|
||||
#include "llvm/Analysis/ConstantFolding.h"
|
||||
#include "llvm/Analysis/Dominators.h"
|
||||
#include "llvm/Analysis/ValueTracking.h"
|
||||
#include "llvm/Analysis/MemoryBuiltins.h"
|
||||
#include "llvm/IR/DataLayout.h"
|
||||
#include "llvm/IR/GlobalAlias.h"
|
||||
#include "llvm/IR/Operator.h"
|
||||
@ -667,8 +667,8 @@ Value *llvm::SimplifyAddInst(Value *Op0, Value *Op1, bool isNSW, bool isNUW,
|
||||
/// This is very similar to GetPointerBaseWithConstantOffset except it doesn't
|
||||
/// follow non-inbounds geps. This allows it to remain usable for icmp ult/etc.
|
||||
/// folding.
|
||||
static Constant *stripAndComputeConstantOffsets(const DataLayout *TD,
|
||||
Value *&V) {
|
||||
static ConstantInt *stripAndComputeConstantOffsets(const DataLayout *TD,
|
||||
Value *&V) {
|
||||
assert(V->getType()->isPointerTy());
|
||||
|
||||
// Without DataLayout, just be conservative for now. Theoretically, more could
|
||||
@ -701,7 +701,7 @@ static Constant *stripAndComputeConstantOffsets(const DataLayout *TD,
|
||||
} while (Visited.insert(V));
|
||||
|
||||
Type *IntPtrTy = TD->getIntPtrType(V->getContext());
|
||||
return ConstantInt::get(IntPtrTy, Offset);
|
||||
return cast<ConstantInt>(ConstantInt::get(IntPtrTy, Offset));
|
||||
}
|
||||
|
||||
/// \brief Compute the constant difference between two pointer values.
|
||||
@ -1689,8 +1689,19 @@ static Value *ExtractEquivalentCondition(Value *V, CmpInst::Predicate Pred,
|
||||
}
|
||||
|
||||
static Constant *computePointerICmp(const DataLayout *TD,
|
||||
const TargetLibraryInfo *TLI,
|
||||
CmpInst::Predicate Pred,
|
||||
Value *LHS, Value *RHS) {
|
||||
// First, skip past any trivial no-ops.
|
||||
LHS = LHS->stripPointerCasts();
|
||||
RHS = RHS->stripPointerCasts();
|
||||
|
||||
// A non-null pointer is not equal to a null pointer.
|
||||
if (llvm::isKnownNonNull(LHS) && isa<ConstantPointerNull>(RHS) &&
|
||||
(Pred == CmpInst::ICMP_EQ || Pred == CmpInst::ICMP_NE))
|
||||
return ConstantInt::get(GetCompareTy(LHS),
|
||||
!CmpInst::isTrueWhenEqual(Pred));
|
||||
|
||||
// We can only fold certain predicates on pointer comparisons.
|
||||
switch (Pred) {
|
||||
default:
|
||||
@ -1713,15 +1724,80 @@ static Constant *computePointerICmp(const DataLayout *TD,
|
||||
break;
|
||||
}
|
||||
|
||||
Constant *LHSOffset = stripAndComputeConstantOffsets(TD, LHS);
|
||||
Constant *RHSOffset = stripAndComputeConstantOffsets(TD, RHS);
|
||||
// Strip off any constant offsets so that we can reason about them.
|
||||
// It's tempting to use getUnderlyingObject or even just stripInBoundsOffsets
|
||||
// here and compare base addresses like AliasAnalysis does, however there are
|
||||
// numerous hazards. AliasAnalysis and its utilities rely on special rules
|
||||
// governing loads and stores which don't apply to icmps. Also, AliasAnalysis
|
||||
// doesn't need to guarantee pointer inequality when it says NoAlias.
|
||||
ConstantInt *LHSOffset = stripAndComputeConstantOffsets(TD, LHS);
|
||||
ConstantInt *RHSOffset = stripAndComputeConstantOffsets(TD, RHS);
|
||||
|
||||
// If LHS and RHS are not related via constant offsets to the same base
|
||||
// value, there is nothing we can do here.
|
||||
if (LHS != RHS)
|
||||
return 0;
|
||||
// If LHS and RHS are related via constant offsets to the same base
|
||||
// value, we can replace it with an icmp which just compares the offsets.
|
||||
if (LHS == RHS)
|
||||
return ConstantExpr::getICmp(Pred, LHSOffset, RHSOffset);
|
||||
|
||||
return ConstantExpr::getICmp(Pred, LHSOffset, RHSOffset);
|
||||
// Various optimizations for (in)equality comparisons.
|
||||
if (Pred == CmpInst::ICMP_EQ || Pred == CmpInst::ICMP_NE) {
|
||||
// Different non-empty allocations that exist at the same time have
|
||||
// different addresses (if the program can tell). Global variables always
|
||||
// exist, so they always exist during the lifetime of each other and all
|
||||
// allocas. Two different allocas usually have different addresses...
|
||||
//
|
||||
// However, if there's an @llvm.stackrestore dynamically in between two
|
||||
// allocas, they may have the same address. It's tempting to reduce the
|
||||
// scope of the problem by only looking at *static* allocas here. That would
|
||||
// cover the majority of allocas while significantly reducing the likelihood
|
||||
// of having an @llvm.stackrestore pop up in the middle. However, it's not
|
||||
// actually impossible for an @llvm.stackrestore to pop up in the middle of
|
||||
// an entry block. Also, if we have a block that's not attached to a
|
||||
// function, we can't tell if it's "static" under the current definition.
|
||||
// Theoretically, this problem could be fixed by creating a new kind of
|
||||
// instruction kind specifically for static allocas. Such a new instruction
|
||||
// could be required to be at the top of the entry block, thus preventing it
|
||||
// from being subject to a @llvm.stackrestore. Instcombine could even
|
||||
// convert regular allocas into these special allocas. It'd be nifty.
|
||||
// However, until then, this problem remains open.
|
||||
//
|
||||
// So, we'll assume that two non-empty allocas have different addresses
|
||||
// for now.
|
||||
//
|
||||
// With all that, if the offsets are within the bounds of their allocations
|
||||
// (and not one-past-the-end! so we can't use inbounds!), and their
|
||||
// allocations aren't the same, the pointers are not equal.
|
||||
//
|
||||
// Note that it's not necessary to check for LHS being a global variable
|
||||
// address, due to canonicalization and constant folding.
|
||||
if (isa<AllocaInst>(LHS) &&
|
||||
(isa<AllocaInst>(RHS) || isa<GlobalVariable>(RHS))) {
|
||||
uint64_t LHSSize, RHSSize;
|
||||
if (getObjectSize(LHS, LHSSize, TD, TLI) &&
|
||||
getObjectSize(RHS, RHSSize, TD, TLI)) {
|
||||
const APInt &LHSOffsetValue = LHSOffset->getValue();
|
||||
const APInt &RHSOffsetValue = RHSOffset->getValue();
|
||||
if (!LHSOffsetValue.isNegative() &&
|
||||
!RHSOffsetValue.isNegative() &&
|
||||
LHSOffsetValue.ult(LHSSize) &&
|
||||
RHSOffsetValue.ult(RHSSize)) {
|
||||
return ConstantInt::get(GetCompareTy(LHS),
|
||||
!CmpInst::isTrueWhenEqual(Pred));
|
||||
}
|
||||
}
|
||||
|
||||
// Repeat the above check but this time without depending on DataLayout
|
||||
// or being able to compute a precise size.
|
||||
if (!cast<PointerType>(LHS->getType())->isEmptyTy() &&
|
||||
!cast<PointerType>(RHS->getType())->isEmptyTy() &&
|
||||
LHSOffset->isNullValue() &&
|
||||
RHSOffset->isNullValue())
|
||||
return ConstantInt::get(GetCompareTy(LHS),
|
||||
!CmpInst::isTrueWhenEqual(Pred));
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise, fail.
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// SimplifyICmpInst - Given operands for an ICmpInst, see if we can
|
||||
@ -1786,50 +1862,6 @@ static Value *SimplifyICmpInst(unsigned Predicate, Value *LHS, Value *RHS,
|
||||
}
|
||||
}
|
||||
|
||||
// icmp <object*>, <object*/null> - Different identified objects have
|
||||
// different addresses (unless null), and what's more the address of an
|
||||
// identified local is never equal to another argument (again, barring null).
|
||||
// Note that generalizing to the case where LHS is a global variable address
|
||||
// or null is pointless, since if both LHS and RHS are constants then we
|
||||
// already constant folded the compare, and if only one of them is then we
|
||||
// moved it to RHS already.
|
||||
Value *LHSPtr = LHS->stripPointerCasts();
|
||||
Value *RHSPtr = RHS->stripPointerCasts();
|
||||
if (LHSPtr == RHSPtr)
|
||||
return ConstantInt::get(ITy, CmpInst::isTrueWhenEqual(Pred));
|
||||
|
||||
// Be more aggressive about stripping pointer adjustments when checking a
|
||||
// comparison of an alloca address to another object. We can rip off all
|
||||
// inbounds GEP operations, even if they are variable.
|
||||
LHSPtr = LHSPtr->stripInBoundsOffsets();
|
||||
if (llvm::isIdentifiedObject(LHSPtr)) {
|
||||
RHSPtr = RHSPtr->stripInBoundsOffsets();
|
||||
if (llvm::isKnownNonNull(LHSPtr) || llvm::isKnownNonNull(RHSPtr)) {
|
||||
// If both sides are different identified objects, they aren't equal
|
||||
// unless they're null.
|
||||
if (LHSPtr != RHSPtr && llvm::isIdentifiedObject(RHSPtr) &&
|
||||
Pred == CmpInst::ICMP_EQ)
|
||||
return ConstantInt::get(ITy, false);
|
||||
|
||||
// A local identified object (alloca or noalias call) can't equal any
|
||||
// incoming argument, unless they're both null or they belong to
|
||||
// different functions. The latter happens during inlining.
|
||||
if (Instruction *LHSInst = dyn_cast<Instruction>(LHSPtr))
|
||||
if (Argument *RHSArg = dyn_cast<Argument>(RHSPtr))
|
||||
if (LHSInst->getParent()->getParent() == RHSArg->getParent() &&
|
||||
Pred == CmpInst::ICMP_EQ)
|
||||
return ConstantInt::get(ITy, false);
|
||||
}
|
||||
|
||||
// Assume that the constant null is on the right.
|
||||
if (llvm::isKnownNonNull(LHSPtr) && isa<ConstantPointerNull>(RHSPtr)) {
|
||||
if (Pred == CmpInst::ICMP_EQ)
|
||||
return ConstantInt::get(ITy, false);
|
||||
else if (Pred == CmpInst::ICMP_NE)
|
||||
return ConstantInt::get(ITy, true);
|
||||
}
|
||||
}
|
||||
|
||||
// If we are comparing with zero then try hard since this is a common case.
|
||||
if (match(RHS, m_Zero())) {
|
||||
bool LHSKnownNonNegative, LHSKnownNegative;
|
||||
@ -2457,7 +2489,7 @@ static Value *SimplifyICmpInst(unsigned Predicate, Value *LHS, Value *RHS,
|
||||
// Simplify comparisons of related pointers using a powerful, recursive
|
||||
// GEP-walk when we have target data available..
|
||||
if (LHS->getType()->isPointerTy())
|
||||
if (Constant *C = computePointerICmp(Q.TD, Pred, LHS, RHS))
|
||||
if (Constant *C = computePointerICmp(Q.TD, Q.TLI, Pred, LHS, RHS))
|
||||
return C;
|
||||
|
||||
if (GetElementPtrInst *GLHS = dyn_cast<GetElementPtrInst>(LHS)) {
|
||||
|
@ -660,3 +660,25 @@ define i1 @alloca_argument_compare(i64* %arg) {
|
||||
; CHECK: alloca_argument_compare
|
||||
; CHECK: ret i1 %cmp
|
||||
}
|
||||
|
||||
; As above, but with the operands reversed.
|
||||
|
||||
define i1 @alloca_argument_compare_swapped(i64* %arg) {
|
||||
%alloc = alloca i64
|
||||
%cmp = icmp eq i64* %alloc, %arg
|
||||
ret i1 %cmp
|
||||
; CHECK: alloca_argument_compare_swapped
|
||||
; CHECK: ret i1 %cmp
|
||||
}
|
||||
|
||||
; Don't assume that a noalias argument isn't equal to a global variable's
|
||||
; address. This is an example where AliasAnalysis' NoAlias concept is
|
||||
; different from actual pointer inequality.
|
||||
|
||||
@y = external global i32
|
||||
define zeroext i1 @external_compare(i32* noalias %x) {
|
||||
%cmp = icmp eq i32* %x, @y
|
||||
ret i1 %cmp
|
||||
; CHECK: external_compare
|
||||
; CHECK: ret i1 %cmp
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user