mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-12-14 11:32:34 +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/Analysis/InstructionSimplify.h"
|
||||||
#include "llvm/ADT/SetVector.h"
|
#include "llvm/ADT/SetVector.h"
|
||||||
#include "llvm/ADT/Statistic.h"
|
#include "llvm/ADT/Statistic.h"
|
||||||
#include "llvm/Analysis/AliasAnalysis.h"
|
|
||||||
#include "llvm/Analysis/ConstantFolding.h"
|
#include "llvm/Analysis/ConstantFolding.h"
|
||||||
#include "llvm/Analysis/Dominators.h"
|
#include "llvm/Analysis/Dominators.h"
|
||||||
#include "llvm/Analysis/ValueTracking.h"
|
#include "llvm/Analysis/ValueTracking.h"
|
||||||
|
#include "llvm/Analysis/MemoryBuiltins.h"
|
||||||
#include "llvm/IR/DataLayout.h"
|
#include "llvm/IR/DataLayout.h"
|
||||||
#include "llvm/IR/GlobalAlias.h"
|
#include "llvm/IR/GlobalAlias.h"
|
||||||
#include "llvm/IR/Operator.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
|
/// This is very similar to GetPointerBaseWithConstantOffset except it doesn't
|
||||||
/// follow non-inbounds geps. This allows it to remain usable for icmp ult/etc.
|
/// follow non-inbounds geps. This allows it to remain usable for icmp ult/etc.
|
||||||
/// folding.
|
/// folding.
|
||||||
static Constant *stripAndComputeConstantOffsets(const DataLayout *TD,
|
static ConstantInt *stripAndComputeConstantOffsets(const DataLayout *TD,
|
||||||
Value *&V) {
|
Value *&V) {
|
||||||
assert(V->getType()->isPointerTy());
|
assert(V->getType()->isPointerTy());
|
||||||
|
|
||||||
// Without DataLayout, just be conservative for now. Theoretically, more could
|
// Without DataLayout, just be conservative for now. Theoretically, more could
|
||||||
@ -701,7 +701,7 @@ static Constant *stripAndComputeConstantOffsets(const DataLayout *TD,
|
|||||||
} while (Visited.insert(V));
|
} while (Visited.insert(V));
|
||||||
|
|
||||||
Type *IntPtrTy = TD->getIntPtrType(V->getContext());
|
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.
|
/// \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,
|
static Constant *computePointerICmp(const DataLayout *TD,
|
||||||
|
const TargetLibraryInfo *TLI,
|
||||||
CmpInst::Predicate Pred,
|
CmpInst::Predicate Pred,
|
||||||
Value *LHS, Value *RHS) {
|
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.
|
// We can only fold certain predicates on pointer comparisons.
|
||||||
switch (Pred) {
|
switch (Pred) {
|
||||||
default:
|
default:
|
||||||
@ -1713,15 +1724,80 @@ static Constant *computePointerICmp(const DataLayout *TD,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
Constant *LHSOffset = stripAndComputeConstantOffsets(TD, LHS);
|
// Strip off any constant offsets so that we can reason about them.
|
||||||
Constant *RHSOffset = stripAndComputeConstantOffsets(TD, RHS);
|
// 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
|
// If LHS and RHS are related via constant offsets to the same base
|
||||||
// value, there is nothing we can do here.
|
// value, we can replace it with an icmp which just compares the offsets.
|
||||||
if (LHS != RHS)
|
if (LHS == RHS)
|
||||||
return 0;
|
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
|
/// 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 we are comparing with zero then try hard since this is a common case.
|
||||||
if (match(RHS, m_Zero())) {
|
if (match(RHS, m_Zero())) {
|
||||||
bool LHSKnownNonNegative, LHSKnownNegative;
|
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
|
// Simplify comparisons of related pointers using a powerful, recursive
|
||||||
// GEP-walk when we have target data available..
|
// GEP-walk when we have target data available..
|
||||||
if (LHS->getType()->isPointerTy())
|
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;
|
return C;
|
||||||
|
|
||||||
if (GetElementPtrInst *GLHS = dyn_cast<GetElementPtrInst>(LHS)) {
|
if (GetElementPtrInst *GLHS = dyn_cast<GetElementPtrInst>(LHS)) {
|
||||||
|
@ -660,3 +660,25 @@ define i1 @alloca_argument_compare(i64* %arg) {
|
|||||||
; CHECK: alloca_argument_compare
|
; CHECK: alloca_argument_compare
|
||||||
; CHECK: ret i1 %cmp
|
; 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