[InstCombine] Fold icmp of gep chain with base (#144065)
Fold icmp between a chain of geps and its base pointer. Previously only
a single gep was supported.
This will be extended to handle the case of two gep chains with a common
base in a followup.
This helps to avoid regressions after #137297.
This commit is contained in:
@@ -708,14 +708,14 @@ Instruction *InstCombinerImpl::foldGEPICmp(GEPOperator *GEPLHS, Value *RHS,
|
||||
return I;
|
||||
};
|
||||
|
||||
Value *PtrBase = GEPLHS->getOperand(0);
|
||||
if (PtrBase == RHS && CanFold(GEPLHS->getNoWrapFlags())) {
|
||||
CommonPointerBase Base = CommonPointerBase::compute(GEPLHS, RHS);
|
||||
if (Base.Ptr == RHS && CanFold(Base.LHSNW)) {
|
||||
// ((gep Ptr, OFFSET) cmp Ptr) ---> (OFFSET cmp 0).
|
||||
GEPNoWrapFlags NW = GEPLHS->getNoWrapFlags();
|
||||
// Do not access GEPLHS after EmitGEPOffset, as the instruction may be
|
||||
// destroyed.
|
||||
Value *Offset = EmitGEPOffset(GEPLHS, /*RewriteGEP=*/true);
|
||||
return NewICmp(NW, Offset, Constant::getNullValue(Offset->getType()));
|
||||
Type *IdxTy = DL.getIndexType(GEPLHS->getType());
|
||||
Value *Offset =
|
||||
EmitGEPOffsets(Base.LHSGEPs, Base.LHSNW, IdxTy, /*RewriteGEPs=*/true);
|
||||
return NewICmp(Base.LHSNW, Offset,
|
||||
Constant::getNullValue(Offset->getType()));
|
||||
}
|
||||
|
||||
if (GEPLHS->isInBounds() && ICmpInst::isEquality(Cond) &&
|
||||
@@ -752,6 +752,7 @@ Instruction *InstCombinerImpl::foldGEPICmp(GEPOperator *GEPLHS, Value *RHS,
|
||||
|
||||
// If the base pointers are different, but the indices are the same, just
|
||||
// compare the base pointer.
|
||||
Value *PtrBase = GEPLHS->getOperand(0);
|
||||
if (PtrBase != GEPRHS->getOperand(0)) {
|
||||
bool IndicesTheSame =
|
||||
GEPLHS->getNumOperands() == GEPRHS->getNumOperands() &&
|
||||
|
||||
@@ -688,9 +688,9 @@ define i32 @test28() nounwind {
|
||||
; CHECK-NEXT: [[INDVAR:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[INDVAR_NEXT:%.*]], [[BB10]] ]
|
||||
; CHECK-NEXT: [[T12_REC:%.*]] = xor i32 [[INDVAR]], -1
|
||||
; CHECK-NEXT: [[TMP0:%.*]] = sext i32 [[T12_REC]] to i64
|
||||
; CHECK-NEXT: [[T12:%.*]] = getelementptr inbounds [[STRUCT_X:%.*]], ptr [[T45]], i64 [[TMP0]]
|
||||
; CHECK-NEXT: [[T12:%.*]] = getelementptr inbounds i8, ptr [[T45]], i64 [[TMP0]]
|
||||
; CHECK-NEXT: [[T16:%.*]] = call i32 (ptr, ...) @printf(ptr noundef nonnull dereferenceable(1) @.str1, ptr nonnull [[T12]]) #[[ATTR0]]
|
||||
; CHECK-NEXT: [[T84:%.*]] = icmp eq ptr [[T12]], [[ORIENTATIONS]]
|
||||
; CHECK-NEXT: [[T84:%.*]] = icmp eq i32 [[INDVAR]], 0
|
||||
; CHECK-NEXT: [[INDVAR_NEXT]] = add i32 [[INDVAR]], 1
|
||||
; CHECK-NEXT: br i1 [[T84]], label [[BB17:%.*]], label [[BB10]]
|
||||
; CHECK: bb17:
|
||||
|
||||
@@ -785,3 +785,67 @@ define i1 @gep_diff_base_same_indices_nuw_nusw(ptr %x, ptr %y, i64 %z) {
|
||||
%cmp = icmp ult ptr %gep1, %gep2
|
||||
ret i1 %cmp
|
||||
}
|
||||
|
||||
define i1 @gep_multiple_eq(ptr %base, i64 %idx, i64 %idx2) {
|
||||
; CHECK-LABEL: @gep_multiple_eq(
|
||||
; CHECK-NEXT: [[GEP1_IDX1:%.*]] = add i64 [[IDX:%.*]], [[IDX2:%.*]]
|
||||
; CHECK-NEXT: [[DOTMASK:%.*]] = and i64 [[GEP1_IDX1]], 4611686018427387903
|
||||
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i64 [[DOTMASK]], 0
|
||||
; CHECK-NEXT: ret i1 [[CMP]]
|
||||
;
|
||||
%gep1 = getelementptr i32, ptr %base, i64 %idx
|
||||
%gep2 = getelementptr i32, ptr %gep1, i64 %idx2
|
||||
%cmp = icmp eq ptr %gep2, %base
|
||||
ret i1 %cmp
|
||||
}
|
||||
|
||||
define i1 @gep_multiple_eq_commuted(ptr %base, i64 %idx, i64 %idx2) {
|
||||
; CHECK-LABEL: @gep_multiple_eq_commuted(
|
||||
; CHECK-NEXT: [[GEP1_IDX1:%.*]] = add i64 [[IDX:%.*]], [[IDX2:%.*]]
|
||||
; CHECK-NEXT: [[DOTMASK:%.*]] = and i64 [[GEP1_IDX1]], 4611686018427387903
|
||||
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i64 [[DOTMASK]], 0
|
||||
; CHECK-NEXT: ret i1 [[CMP]]
|
||||
;
|
||||
%gep1 = getelementptr i32, ptr %base, i64 %idx
|
||||
%gep2 = getelementptr i32, ptr %gep1, i64 %idx2
|
||||
%cmp = icmp eq ptr %base, %gep2
|
||||
ret i1 %cmp
|
||||
}
|
||||
|
||||
define i1 @gep_mugtiple_ugt_nuw(ptr %base, i64 %idx, i64 %idx2) {
|
||||
; CHECK-LABEL: @gep_mugtiple_ugt_nuw(
|
||||
; CHECK-NEXT: [[GEP1_IDX1:%.*]] = sub i64 0, [[IDX2:%.*]]
|
||||
; CHECK-NEXT: [[CMP:%.*]] = icmp ne i64 [[IDX:%.*]], [[GEP1_IDX1]]
|
||||
; CHECK-NEXT: ret i1 [[CMP]]
|
||||
;
|
||||
%gep1 = getelementptr nuw i32, ptr %base, i64 %idx
|
||||
%gep2 = getelementptr nuw i32, ptr %gep1, i64 %idx2
|
||||
%cmp = icmp ugt ptr %gep2, %base
|
||||
ret i1 %cmp
|
||||
}
|
||||
|
||||
define i1 @gep_mugtiple_ugt_not_all_nuw(ptr %base, i64 %idx, i64 %idx2) {
|
||||
; CHECK-LABEL: @gep_mugtiple_ugt_not_all_nuw(
|
||||
; CHECK-NEXT: [[GEP1:%.*]] = getelementptr nuw i32, ptr [[BASE:%.*]], i64 [[IDX:%.*]]
|
||||
; CHECK-NEXT: [[GEP2:%.*]] = getelementptr i32, ptr [[GEP1]], i64 [[IDX2:%.*]]
|
||||
; CHECK-NEXT: [[CMP:%.*]] = icmp ugt ptr [[GEP2]], [[BASE]]
|
||||
; CHECK-NEXT: ret i1 [[CMP]]
|
||||
;
|
||||
%gep1 = getelementptr nuw i32, ptr %base, i64 %idx
|
||||
%gep2 = getelementptr i32, ptr %gep1, i64 %idx2
|
||||
%cmp = icmp ugt ptr %gep2, %base
|
||||
ret i1 %cmp
|
||||
}
|
||||
|
||||
define i1 @gep_mugtiple_ugt_inbounds_nusw(ptr %base, i64 %idx, i64 %idx2) {
|
||||
; CHECK-LABEL: @gep_mugtiple_ugt_inbounds_nusw(
|
||||
; CHECK-NEXT: [[GEP1_IDX1:%.*]] = add i64 [[IDX:%.*]], [[IDX2:%.*]]
|
||||
; CHECK-NEXT: [[TMP1:%.*]] = shl i64 [[GEP1_IDX1]], 2
|
||||
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i64 [[TMP1]], 0
|
||||
; CHECK-NEXT: ret i1 [[CMP]]
|
||||
;
|
||||
%gep1 = getelementptr inbounds i32, ptr %base, i64 %idx
|
||||
%gep2 = getelementptr nusw i32, ptr %gep1, i64 %idx2
|
||||
%cmp = icmp ugt ptr %gep2, %base
|
||||
ret i1 %cmp
|
||||
}
|
||||
|
||||
@@ -7,9 +7,7 @@ target datalayout = "p:32:32"
|
||||
|
||||
define i1 @test(ptr %p, i32 %n) {
|
||||
; CHECK-LABEL: @test(
|
||||
; CHECK-NEXT: [[END:%.*]] = getelementptr inbounds [0 x %S], ptr [[P:%.*]], i32 0, i32 [[N:%.*]], i32 0, i32 0
|
||||
; CHECK-NEXT: [[LAST:%.*]] = getelementptr inbounds i8, ptr [[END]], i32 -8
|
||||
; CHECK-NEXT: [[CMP:%.*]] = icmp eq ptr [[LAST]], [[P]]
|
||||
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[N:%.*]], 1
|
||||
; CHECK-NEXT: ret i1 [[CMP]]
|
||||
;
|
||||
%end = getelementptr inbounds [0 x %S], ptr %p, i32 0, i32 %n, i32 0, i32 0
|
||||
@@ -22,9 +20,7 @@ define i1 @test(ptr %p, i32 %n) {
|
||||
define i1 @test64(ptr %p, i64 %n) {
|
||||
; CHECK-LABEL: @test64(
|
||||
; CHECK-NEXT: [[TMP1:%.*]] = trunc i64 [[N:%.*]] to i32
|
||||
; CHECK-NEXT: [[END:%.*]] = getelementptr inbounds [0 x %S], ptr [[P:%.*]], i32 0, i32 [[TMP1]], i32 0, i32 0
|
||||
; CHECK-NEXT: [[LAST:%.*]] = getelementptr inbounds i8, ptr [[END]], i32 -8
|
||||
; CHECK-NEXT: [[CMP:%.*]] = icmp eq ptr [[LAST]], [[P]]
|
||||
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[TMP1]], 1
|
||||
; CHECK-NEXT: ret i1 [[CMP]]
|
||||
;
|
||||
%end = getelementptr inbounds [0 x %S], ptr %p, i64 0, i64 %n, i32 0, i64 0
|
||||
@@ -37,9 +33,7 @@ define i1 @test64(ptr %p, i64 %n) {
|
||||
define i1 @test64_overflow(ptr %p, i64 %n) {
|
||||
; CHECK-LABEL: @test64_overflow(
|
||||
; CHECK-NEXT: [[TMP1:%.*]] = trunc i64 [[N:%.*]] to i32
|
||||
; CHECK-NEXT: [[END:%.*]] = getelementptr inbounds [0 x %S], ptr [[P:%.*]], i32 0, i32 [[TMP1]], i32 0, i32 0
|
||||
; CHECK-NEXT: [[LAST:%.*]] = getelementptr inbounds i8, ptr [[END]], i32 -8
|
||||
; CHECK-NEXT: [[CMP:%.*]] = icmp eq ptr [[LAST]], [[P]]
|
||||
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[TMP1]], 1
|
||||
; CHECK-NEXT: ret i1 [[CMP]]
|
||||
;
|
||||
%end = getelementptr inbounds [0 x %S], ptr %p, i64 0, i64 %n, i32 0, i64 8589934592
|
||||
|
||||
Reference in New Issue
Block a user