-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[InstCombine] Make indexed compare fold GEP source type independent #71663
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
Merged
Merged
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
3748dfe
[InstCombine] Make indexed compare fold GEP source type independent
nikic a2b4bb7
Use stripAndAccumulateConstantOffsets()
nikic 79c3ce2
remove dead code
nikic d3f9de6
Simplify check for at most one variable index
nikic af6cc8f
Restore inbounds check
nikic File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -18,6 +18,7 @@ | |
#include "llvm/Analysis/CmpInstAnalysis.h" | ||
#include "llvm/Analysis/ConstantFolding.h" | ||
#include "llvm/Analysis/InstructionSimplify.h" | ||
#include "llvm/Analysis/Utils/Local.h" | ||
#include "llvm/Analysis/VectorUtils.h" | ||
#include "llvm/IR/ConstantRange.h" | ||
#include "llvm/IR/DataLayout.h" | ||
|
@@ -413,7 +414,7 @@ Instruction *InstCombinerImpl::foldCmpLoadFromIndexedGlobal( | |
/// Returns true if we can rewrite Start as a GEP with pointer Base | ||
/// and some integer offset. The nodes that need to be re-written | ||
/// for this transformation will be added to Explored. | ||
static bool canRewriteGEPAsOffset(Type *ElemTy, Value *Start, Value *Base, | ||
static bool canRewriteGEPAsOffset(Value *Start, Value *Base, | ||
const DataLayout &DL, | ||
SetVector<Value *> &Explored) { | ||
SmallVector<Value *, 16> WorkList(1, Start); | ||
|
@@ -447,11 +448,9 @@ static bool canRewriteGEPAsOffset(Type *ElemTy, Value *Start, Value *Base, | |
return false; | ||
|
||
if (auto *GEP = dyn_cast<GEPOperator>(V)) { | ||
// We're limiting the GEP to having one index. This will preserve | ||
// the original pointer type. We could handle more cases in the | ||
// future. | ||
if (GEP->getNumIndices() != 1 || !GEP->isInBounds() || | ||
GEP->getSourceElementType() != ElemTy) | ||
// Only allow inbounds GEPs with at most one variable offset. | ||
auto IsNonConst = [](Value *V) { return !isa<ConstantInt>(V); }; | ||
if (!GEP->isInBounds() || count_if(GEP->indices(), IsNonConst) > 1) | ||
return false; | ||
|
||
if (!Explored.contains(GEP->getOperand(0))) | ||
|
@@ -528,7 +527,7 @@ static void setInsertionPoint(IRBuilder<> &Builder, Value *V, | |
|
||
/// Returns a re-written value of Start as an indexed GEP using Base as a | ||
/// pointer. | ||
static Value *rewriteGEPAsOffset(Type *ElemTy, Value *Start, Value *Base, | ||
static Value *rewriteGEPAsOffset(Value *Start, Value *Base, | ||
const DataLayout &DL, | ||
SetVector<Value *> &Explored, | ||
InstCombiner &IC) { | ||
|
@@ -559,29 +558,18 @@ static Value *rewriteGEPAsOffset(Type *ElemTy, Value *Start, Value *Base, | |
|
||
// Create all the other instructions. | ||
for (Value *Val : Explored) { | ||
|
||
if (NewInsts.contains(Val)) | ||
continue; | ||
|
||
if (auto *GEP = dyn_cast<GEPOperator>(Val)) { | ||
Value *Index = NewInsts[GEP->getOperand(1)] ? NewInsts[GEP->getOperand(1)] | ||
: GEP->getOperand(1); | ||
setInsertionPoint(Builder, GEP); | ||
// Indices might need to be sign extended. GEPs will magically do | ||
// this, but we need to do it ourselves here. | ||
if (Index->getType()->getScalarSizeInBits() != | ||
NewInsts[GEP->getOperand(0)]->getType()->getScalarSizeInBits()) { | ||
Index = Builder.CreateSExtOrTrunc( | ||
Index, NewInsts[GEP->getOperand(0)]->getType(), | ||
GEP->getOperand(0)->getName() + ".sext"); | ||
} | ||
|
||
auto *Op = NewInsts[GEP->getOperand(0)]; | ||
Value *Op = NewInsts[GEP->getOperand(0)]; | ||
Value *OffsetV = emitGEPOffset(&Builder, DL, GEP); | ||
if (isa<ConstantInt>(Op) && cast<ConstantInt>(Op)->isZero()) | ||
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. nit: |
||
NewInsts[GEP] = Index; | ||
NewInsts[GEP] = OffsetV; | ||
else | ||
NewInsts[GEP] = Builder.CreateNSWAdd( | ||
Op, Index, GEP->getOperand(0)->getName() + ".add"); | ||
Op, OffsetV, GEP->getOperand(0)->getName() + ".add"); | ||
continue; | ||
} | ||
if (isa<PHINode>(Val)) | ||
|
@@ -609,23 +597,14 @@ static Value *rewriteGEPAsOffset(Type *ElemTy, Value *Start, Value *Base, | |
} | ||
} | ||
|
||
PointerType *PtrTy = PointerType::get( | ||
Base->getContext(), Start->getType()->getPointerAddressSpace()); | ||
for (Value *Val : Explored) { | ||
if (Val == Base) | ||
continue; | ||
|
||
// Depending on the type, for external users we have to emit | ||
// a GEP or a GEP + ptrtoint. | ||
setInsertionPoint(Builder, Val, false); | ||
|
||
// Cast base to the expected type. | ||
Value *NewVal = Builder.CreateBitOrPointerCast( | ||
Base, PtrTy, Start->getName() + "to.ptr"); | ||
NewVal = Builder.CreateInBoundsGEP(ElemTy, NewVal, ArrayRef(NewInsts[Val]), | ||
Val->getName() + ".ptr"); | ||
NewVal = Builder.CreateBitOrPointerCast( | ||
NewVal, Val->getType(), Val->getName() + ".conv"); | ||
// Create GEP for external users. | ||
dtcxzyw marked this conversation as resolved.
Show resolved
Hide resolved
|
||
Value *NewVal = Builder.CreateInBoundsGEP( | ||
Builder.getInt8Ty(), Base, NewInsts[Val], Val->getName() + ".ptr"); | ||
IC.replaceInstUsesWith(*cast<Instruction>(Val), NewVal); | ||
// Add old instruction to worklist for DCE. We don't directly remove it | ||
// here because the original compare is one of the users. | ||
|
@@ -635,32 +614,6 @@ static Value *rewriteGEPAsOffset(Type *ElemTy, Value *Start, Value *Base, | |
return NewInsts[Start]; | ||
} | ||
|
||
/// Looks through GEPs in order to express the input Value as a constant | ||
/// indexed GEP. Returns a pair containing the GEPs Pointer and Index. | ||
static std::pair<Value *, Value *> | ||
getAsConstantIndexedAddress(Type *ElemTy, Value *V, const DataLayout &DL) { | ||
Type *IndexType = IntegerType::get(V->getContext(), | ||
DL.getIndexTypeSizeInBits(V->getType())); | ||
|
||
Constant *Index = ConstantInt::getNullValue(IndexType); | ||
while (GEPOperator *GEP = dyn_cast<GEPOperator>(V)) { | ||
// We accept only inbouds GEPs here to exclude the possibility of | ||
// overflow. | ||
if (!GEP->isInBounds()) | ||
break; | ||
if (GEP->hasAllConstantIndices() && GEP->getNumIndices() == 1 && | ||
GEP->getSourceElementType() == ElemTy && | ||
GEP->getOperand(1)->getType() == IndexType) { | ||
V = GEP->getOperand(0); | ||
Constant *GEPIndex = static_cast<Constant *>(GEP->getOperand(1)); | ||
Index = ConstantExpr::getAdd(Index, GEPIndex); | ||
continue; | ||
} | ||
break; | ||
} | ||
return {V, Index}; | ||
} | ||
|
||
/// Converts (CMP GEPLHS, RHS) if this change would make RHS a constant. | ||
/// We can look through PHIs, GEPs and casts in order to determine a common base | ||
/// between GEPLHS and RHS. | ||
|
@@ -675,14 +628,19 @@ static Instruction *transformToIndexedCompare(GEPOperator *GEPLHS, Value *RHS, | |
if (!GEPLHS->hasAllConstantIndices()) | ||
return nullptr; | ||
|
||
Type *ElemTy = GEPLHS->getSourceElementType(); | ||
Value *PtrBase, *Index; | ||
std::tie(PtrBase, Index) = getAsConstantIndexedAddress(ElemTy, GEPLHS, DL); | ||
APInt Offset(DL.getIndexTypeSizeInBits(GEPLHS->getType()), 0); | ||
Value *PtrBase = | ||
GEPLHS->stripAndAccumulateConstantOffsets(DL, Offset, | ||
/*AllowNonInbounds*/ false); | ||
|
||
// Bail if we looked through addrspacecast. | ||
if (PtrBase->getType() != GEPLHS->getType()) | ||
return nullptr; | ||
|
||
// The set of nodes that will take part in this transformation. | ||
SetVector<Value *> Nodes; | ||
|
||
if (!canRewriteGEPAsOffset(ElemTy, RHS, PtrBase, DL, Nodes)) | ||
if (!canRewriteGEPAsOffset(RHS, PtrBase, DL, Nodes)) | ||
return nullptr; | ||
|
||
// We know we can re-write this as | ||
|
@@ -691,13 +649,14 @@ static Instruction *transformToIndexedCompare(GEPOperator *GEPLHS, Value *RHS, | |
// can't have overflow on either side. We can therefore re-write | ||
// this as: | ||
// OFFSET1 cmp OFFSET2 | ||
Value *NewRHS = rewriteGEPAsOffset(ElemTy, RHS, PtrBase, DL, Nodes, IC); | ||
Value *NewRHS = rewriteGEPAsOffset(RHS, PtrBase, DL, Nodes, IC); | ||
|
||
// RewriteGEPAsOffset has replaced RHS and all of its uses with a re-written | ||
// GEP having PtrBase as the pointer base, and has returned in NewRHS the | ||
// offset. Since Index is the offset of LHS to the base pointer, we will now | ||
// compare the offsets instead of comparing the pointers. | ||
return new ICmpInst(ICmpInst::getSignedPredicate(Cond), Index, NewRHS); | ||
return new ICmpInst(ICmpInst::getSignedPredicate(Cond), | ||
IC.Builder.getInt(Offset), NewRHS); | ||
} | ||
|
||
/// Fold comparisons between a GEP instruction and something else. At this point | ||
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.