-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[InstCombine] Support ptrtoint of gep folds for chain of geps #137323
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
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 | ||||
---|---|---|---|---|---|---|
|
@@ -2067,6 +2067,42 @@ Instruction *InstCombinerImpl::visitIntToPtr(IntToPtrInst &CI) { | |||||
return nullptr; | ||||||
} | ||||||
|
||||||
Value *InstCombinerImpl::foldPtrToIntOfGEP(Type *IntTy, Value *Ptr) { | ||||||
// Look through chain of one-use GEPs. | ||||||
Type *PtrTy = Ptr->getType(); | ||||||
SmallVector<GEPOperator *> GEPs; | ||||||
while (true) { | ||||||
auto *GEP = dyn_cast<GEPOperator>(Ptr); | ||||||
if (!GEP || !GEP->hasOneUse()) | ||||||
break; | ||||||
GEPs.push_back(GEP); | ||||||
Ptr = GEP->getPointerOperand(); | ||||||
} | ||||||
|
||||||
// Don't handle case where GEP converts from pointer to vector. | ||||||
if (GEPs.empty() || PtrTy != Ptr->getType()) | ||||||
return nullptr; | ||||||
|
||||||
// Check whether we know the integer value of the base pointer. | ||||||
Value *Res; | ||||||
Type *IdxTy = DL.getIndexType(PtrTy); | ||||||
if (match(Ptr, m_OneUse(m_IntToPtr(m_Value(Res)))) && | ||||||
Res->getType() == IntTy && IntTy == IdxTy) { | ||||||
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.
Suggested change
If 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. I think this is correct, but it's worth noting that we can only run into this if the inttoptr hasn't been canonicalized yet (otherwise it would be guaranteed to use IntTy), so it's not really possible to test this case. |
||||||
// pass | ||||||
} else if (isa<ConstantPointerNull>(Ptr)) { | ||||||
Res = Constant::getNullValue(IdxTy); | ||||||
} else { | ||||||
return nullptr; | ||||||
} | ||||||
|
||||||
// Perform the entire operation on integers instead. | ||||||
for (GEPOperator *GEP : reverse(GEPs)) { | ||||||
Value *Offset = EmitGEPOffset(GEP); | ||||||
Res = Builder.CreateAdd(Res, Offset, "", GEP->hasNoUnsignedWrap()); | ||||||
} | ||||||
return Builder.CreateZExtOrTrunc(Res, IntTy); | ||||||
} | ||||||
|
||||||
Instruction *InstCombinerImpl::visitPtrToInt(PtrToIntInst &CI) { | ||||||
// If the destination integer type is not the intptr_t type for this target, | ||||||
// do a ptrtoint to intptr_t then do a trunc or zext. This allows the cast | ||||||
|
@@ -2093,29 +2129,8 @@ Instruction *InstCombinerImpl::visitPtrToInt(PtrToIntInst &CI) { | |||||
Mask->getType() == Ty) | ||||||
return BinaryOperator::CreateAnd(Builder.CreatePtrToInt(Ptr, Ty), Mask); | ||||||
|
||||||
if (auto *GEP = dyn_cast<GEPOperator>(SrcOp)) { | ||||||
// Fold ptrtoint(gep null, x) to multiply + constant if the GEP has one use. | ||||||
// While this can increase the number of instructions it doesn't actually | ||||||
// increase the overall complexity since the arithmetic is just part of | ||||||
// the GEP otherwise. | ||||||
if (GEP->hasOneUse() && | ||||||
isa<ConstantPointerNull>(GEP->getPointerOperand())) { | ||||||
return replaceInstUsesWith(CI, | ||||||
Builder.CreateIntCast(EmitGEPOffset(GEP), Ty, | ||||||
/*isSigned=*/false)); | ||||||
} | ||||||
|
||||||
// (ptrtoint (gep (inttoptr Base), ...)) -> Base + Offset | ||||||
Value *Base; | ||||||
if (GEP->hasOneUse() && | ||||||
match(GEP->getPointerOperand(), m_OneUse(m_IntToPtr(m_Value(Base)))) && | ||||||
Base->getType() == Ty) { | ||||||
Value *Offset = EmitGEPOffset(GEP); | ||||||
auto *NewOp = BinaryOperator::CreateAdd(Base, Offset); | ||||||
NewOp->setHasNoUnsignedWrap(GEP->hasNoUnsignedWrap()); | ||||||
return NewOp; | ||||||
} | ||||||
} | ||||||
if (Value *V = foldPtrToIntOfGEP(Ty, SrcOp)) | ||||||
return replaceInstUsesWith(CI, V); | ||||||
|
||||||
Value *Vec, *Scalar, *Index; | ||||||
if (match(SrcOp, m_OneUse(m_InsertElt(m_IntToPtr(m_Value(Vec)), | ||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing test for the multi-use case. Do we need a one-use constraint on inttoptr?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is pre-existing code tested here:
llvm-project/llvm/test/Transforms/InstCombine/cast_ptr.ll
Lines 406 to 419 in cd7497b
I agree that this one-use requirement is unnecessary.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks like removing this one-use check has some negative interaction with the indexed compare fold.