Skip to content

Commit 50aacb9

Browse files
authored
[InstCombine] Support ptrtoint of gep folds for chain of geps (#137323)
Support the ptrtoint(gep null, x) -> x and ptrtoint(gep inttoptr(x), y) -> x+y folds for the case where there is a chain of geps that ends in null or inttoptr. This avoids some regressions from #137297. While here, also be a bit more careful about edge cases like pointer to vector splats and mismatched pointer and index size.
1 parent dae63e2 commit 50aacb9

File tree

3 files changed

+140
-24
lines changed

3 files changed

+140
-24
lines changed

llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp

Lines changed: 38 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2067,6 +2067,42 @@ Instruction *InstCombinerImpl::visitIntToPtr(IntToPtrInst &CI) {
20672067
return nullptr;
20682068
}
20692069

2070+
Value *InstCombinerImpl::foldPtrToIntOfGEP(Type *IntTy, Value *Ptr) {
2071+
// Look through chain of one-use GEPs.
2072+
Type *PtrTy = Ptr->getType();
2073+
SmallVector<GEPOperator *> GEPs;
2074+
while (true) {
2075+
auto *GEP = dyn_cast<GEPOperator>(Ptr);
2076+
if (!GEP || !GEP->hasOneUse())
2077+
break;
2078+
GEPs.push_back(GEP);
2079+
Ptr = GEP->getPointerOperand();
2080+
}
2081+
2082+
// Don't handle case where GEP converts from pointer to vector.
2083+
if (GEPs.empty() || PtrTy != Ptr->getType())
2084+
return nullptr;
2085+
2086+
// Check whether we know the integer value of the base pointer.
2087+
Value *Res;
2088+
Type *IdxTy = DL.getIndexType(PtrTy);
2089+
if (match(Ptr, m_OneUse(m_IntToPtr(m_Value(Res)))) &&
2090+
Res->getType() == IntTy && IntTy == IdxTy) {
2091+
// pass
2092+
} else if (isa<ConstantPointerNull>(Ptr)) {
2093+
Res = Constant::getNullValue(IdxTy);
2094+
} else {
2095+
return nullptr;
2096+
}
2097+
2098+
// Perform the entire operation on integers instead.
2099+
for (GEPOperator *GEP : reverse(GEPs)) {
2100+
Value *Offset = EmitGEPOffset(GEP);
2101+
Res = Builder.CreateAdd(Res, Offset, "", GEP->hasNoUnsignedWrap());
2102+
}
2103+
return Builder.CreateZExtOrTrunc(Res, IntTy);
2104+
}
2105+
20702106
Instruction *InstCombinerImpl::visitPtrToInt(PtrToIntInst &CI) {
20712107
// If the destination integer type is not the intptr_t type for this target,
20722108
// 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) {
20932129
Mask->getType() == Ty)
20942130
return BinaryOperator::CreateAnd(Builder.CreatePtrToInt(Ptr, Ty), Mask);
20952131

2096-
if (auto *GEP = dyn_cast<GEPOperator>(SrcOp)) {
2097-
// Fold ptrtoint(gep null, x) to multiply + constant if the GEP has one use.
2098-
// While this can increase the number of instructions it doesn't actually
2099-
// increase the overall complexity since the arithmetic is just part of
2100-
// the GEP otherwise.
2101-
if (GEP->hasOneUse() &&
2102-
isa<ConstantPointerNull>(GEP->getPointerOperand())) {
2103-
return replaceInstUsesWith(CI,
2104-
Builder.CreateIntCast(EmitGEPOffset(GEP), Ty,
2105-
/*isSigned=*/false));
2106-
}
2107-
2108-
// (ptrtoint (gep (inttoptr Base), ...)) -> Base + Offset
2109-
Value *Base;
2110-
if (GEP->hasOneUse() &&
2111-
match(GEP->getPointerOperand(), m_OneUse(m_IntToPtr(m_Value(Base)))) &&
2112-
Base->getType() == Ty) {
2113-
Value *Offset = EmitGEPOffset(GEP);
2114-
auto *NewOp = BinaryOperator::CreateAdd(Base, Offset);
2115-
NewOp->setHasNoUnsignedWrap(GEP->hasNoUnsignedWrap());
2116-
return NewOp;
2117-
}
2118-
}
2132+
if (Value *V = foldPtrToIntOfGEP(Ty, SrcOp))
2133+
return replaceInstUsesWith(CI, V);
21192134

21202135
Value *Vec, *Scalar, *Index;
21212136
if (match(SrcOp, m_OneUse(m_InsertElt(m_IntToPtr(m_Value(Vec)),

llvm/lib/Transforms/InstCombine/InstCombineInternal.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -661,6 +661,7 @@ class LLVM_LIBRARY_VISIBILITY InstCombinerImpl final
661661
/// folded operation.
662662
void PHIArgMergedDebugLoc(Instruction *Inst, PHINode &PN);
663663

664+
Value *foldPtrToIntOfGEP(Type *IntTy, Value *Ptr);
664665
Instruction *foldGEPICmp(GEPOperator *GEPLHS, Value *RHS, CmpPredicate Cond,
665666
Instruction &I);
666667
Instruction *foldSelectICmp(CmpPredicate Pred, SelectInst *SI, Value *RHS,

llvm/test/Transforms/InstCombine/cast_ptr.ll

Lines changed: 101 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
; Tests to make sure elimination of casts is working correctly
33
; RUN: opt < %s -passes=instcombine -S | FileCheck %s
44

5-
target datalayout = "p:32:32-p1:32:32-p2:16:16"
5+
target datalayout = "p:32:32-p1:32:32-p2:16:16-p3:32:32:32:16"
66

77
@global = global i8 0
88

@@ -432,3 +432,103 @@ define i32 @ptr_add_in_int_extra_use2(i32 %x) {
432432
%r = ptrtoint ptr %p2 to i32
433433
ret i32 %r
434434
}
435+
436+
define i32 @ptrtoint_of_inttoptr_multiple_gep(i32 %x, i32 %y, i32 %z) {
437+
; CHECK-LABEL: @ptrtoint_of_inttoptr_multiple_gep(
438+
; CHECK-NEXT: [[PTR2_IDX:%.*]] = shl nuw i32 [[Y:%.*]], 1
439+
; CHECK-NEXT: [[TMP1:%.*]] = add nuw i32 [[X:%.*]], [[PTR2_IDX]]
440+
; CHECK-NEXT: [[PTR3_IDX:%.*]] = shl i32 [[Z:%.*]], 2
441+
; CHECK-NEXT: [[R:%.*]] = add i32 [[TMP1]], [[PTR3_IDX]]
442+
; CHECK-NEXT: ret i32 [[R]]
443+
;
444+
%ptr = inttoptr i32 %x to ptr
445+
%ptr2 = getelementptr nuw i16, ptr %ptr, i32 %y
446+
%ptr3 = getelementptr i32, ptr %ptr2, i32 %z
447+
%r = ptrtoint ptr %ptr3 to i32
448+
ret i32 %r
449+
}
450+
451+
define i32 @ptrtoint_of_inttoptr_multiple_gep_extra_use(i32 %x, i32 %y, i32 %z) {
452+
; CHECK-LABEL: @ptrtoint_of_inttoptr_multiple_gep_extra_use(
453+
; CHECK-NEXT: [[PTR:%.*]] = inttoptr i32 [[X:%.*]] to ptr
454+
; CHECK-NEXT: [[PTR2:%.*]] = getelementptr i16, ptr [[PTR]], i32 [[Y:%.*]]
455+
; CHECK-NEXT: call void @use_ptr(ptr [[PTR2]])
456+
; CHECK-NEXT: [[PTR3:%.*]] = getelementptr i32, ptr [[PTR2]], i32 [[Z:%.*]]
457+
; CHECK-NEXT: [[R:%.*]] = ptrtoint ptr [[PTR3]] to i32
458+
; CHECK-NEXT: ret i32 [[R]]
459+
;
460+
%ptr = inttoptr i32 %x to ptr
461+
%ptr2 = getelementptr i16, ptr %ptr, i32 %y
462+
call void @use_ptr(ptr %ptr2)
463+
%ptr3 = getelementptr i32, ptr %ptr2, i32 %z
464+
%r = ptrtoint ptr %ptr3 to i32
465+
ret i32 %r
466+
}
467+
468+
define i32 @ptrtoint_of_inttoptr_index_type(i32 %x, i16 %y) {
469+
; CHECK-LABEL: @ptrtoint_of_inttoptr_index_type(
470+
; CHECK-NEXT: [[PTR:%.*]] = inttoptr i32 [[X:%.*]] to ptr addrspace(3)
471+
; CHECK-NEXT: [[PTR2:%.*]] = getelementptr i16, ptr addrspace(3) [[PTR]], i16 [[Y:%.*]]
472+
; CHECK-NEXT: [[R:%.*]] = ptrtoint ptr addrspace(3) [[PTR2]] to i32
473+
; CHECK-NEXT: ret i32 [[R]]
474+
;
475+
%ptr = inttoptr i32 %x to ptr addrspace(3)
476+
%ptr2 = getelementptr i16, ptr addrspace(3) %ptr, i16 %y
477+
%r = ptrtoint ptr addrspace(3) %ptr2 to i32
478+
ret i32 %r
479+
}
480+
481+
define i32 @ptrtoint_of_null_multiple_gep(i32 %x, i32 %y, i32 %z) {
482+
; CHECK-LABEL: @ptrtoint_of_null_multiple_gep(
483+
; CHECK-NEXT: [[PTR2_IDX:%.*]] = shl i32 [[X:%.*]], 1
484+
; CHECK-NEXT: [[PTR3_IDX:%.*]] = shl nuw i32 [[Y:%.*]], 2
485+
; CHECK-NEXT: [[TMP1:%.*]] = add nuw i32 [[PTR2_IDX]], [[PTR3_IDX]]
486+
; CHECK-NEXT: [[PTR4_IDX:%.*]] = shl i32 [[Z:%.*]], 3
487+
; CHECK-NEXT: [[R:%.*]] = add i32 [[TMP1]], [[PTR4_IDX]]
488+
; CHECK-NEXT: ret i32 [[R]]
489+
;
490+
%ptr2 = getelementptr i16, ptr null, i32 %x
491+
%ptr3 = getelementptr nuw i32, ptr %ptr2, i32 %y
492+
%ptr4 = getelementptr i64, ptr %ptr3, i32 %z
493+
%r = ptrtoint ptr %ptr4 to i32
494+
ret i32 %r
495+
}
496+
497+
define i32 @ptrtoint_of_null_multiple_gep_extra_use(i32 %x, i32 %y, i32 %z) {
498+
; CHECK-LABEL: @ptrtoint_of_null_multiple_gep_extra_use(
499+
; CHECK-NEXT: [[PTR2:%.*]] = getelementptr i16, ptr null, i32 [[X:%.*]]
500+
; CHECK-NEXT: call void @use_ptr(ptr [[PTR2]])
501+
; CHECK-NEXT: [[PTR3:%.*]] = getelementptr nuw i32, ptr [[PTR2]], i32 [[Y:%.*]]
502+
; CHECK-NEXT: [[PTR4:%.*]] = getelementptr i64, ptr [[PTR3]], i32 [[Z:%.*]]
503+
; CHECK-NEXT: [[R:%.*]] = ptrtoint ptr [[PTR4]] to i32
504+
; CHECK-NEXT: ret i32 [[R]]
505+
;
506+
%ptr2 = getelementptr i16, ptr null, i32 %x
507+
call void @use_ptr(ptr %ptr2)
508+
%ptr3 = getelementptr nuw i32, ptr %ptr2, i32 %y
509+
%ptr4 = getelementptr i64, ptr %ptr3, i32 %z
510+
%r = ptrtoint ptr %ptr4 to i32
511+
ret i32 %r
512+
}
513+
514+
define i32 @ptrtoint_of_null_index_type(i16 %x) {
515+
; CHECK-LABEL: @ptrtoint_of_null_index_type(
516+
; CHECK-NEXT: [[PTR_IDX:%.*]] = shl i16 [[X:%.*]], 1
517+
; CHECK-NEXT: [[R:%.*]] = zext i16 [[PTR_IDX]] to i32
518+
; CHECK-NEXT: ret i32 [[R]]
519+
;
520+
%ptr = getelementptr i16, ptr addrspace(3) null, i16 %x
521+
%r = ptrtoint ptr addrspace(3) %ptr to i32
522+
ret i32 %r
523+
}
524+
525+
define <2 x i32> @ptrtoint_of_null_splat(<2 x i16> %x) {
526+
; CHECK-LABEL: @ptrtoint_of_null_splat(
527+
; CHECK-NEXT: [[PTR:%.*]] = getelementptr i16, ptr addrspace(3) null, <2 x i16> [[X:%.*]]
528+
; CHECK-NEXT: [[R:%.*]] = ptrtoint <2 x ptr addrspace(3)> [[PTR]] to <2 x i32>
529+
; CHECK-NEXT: ret <2 x i32> [[R]]
530+
;
531+
%ptr = getelementptr i16, ptr addrspace(3) null, <2 x i16> %x
532+
%r = ptrtoint <2 x ptr addrspace(3)> %ptr to <2 x i32>
533+
ret <2 x i32> %r
534+
}

0 commit comments

Comments
 (0)