Skip to content

Commit fef6e3f

Browse files
committed
[InstCombine] Don't require GEP in indexed compare fold
The indexed compare fold folds comparisons like p+a == p+b to a == b, even in cases where the a/b are complex (e.g. via multiple geps, or phis). Currently, it requires that the LHS is actually a GEP, but this requirement isn't really necessary: We can handle the pattern p == p+b as well. This patch removes the GEP requirement, allowing additional comparisons to be optimized away.
1 parent 07292b7 commit fef6e3f

File tree

5 files changed

+52
-54
lines changed

5 files changed

+52
-54
lines changed

llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp

Lines changed: 16 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -619,27 +619,27 @@ static Value *rewriteGEPAsOffset(Value *Start, Value *Base,
619619
return NewInsts[Start];
620620
}
621621

622-
/// Converts (CMP GEPLHS, RHS) if this change would make RHS a constant.
622+
/// Converts (CMP LHS, RHS) if this change would make RHS a constant.
623623
/// We can look through PHIs, GEPs and casts in order to determine a common base
624-
/// between GEPLHS and RHS.
625-
static Instruction *transformToIndexedCompare(GEPOperator *GEPLHS, Value *RHS,
624+
/// between LHS and RHS.
625+
static Instruction *transformToIndexedCompare(Value *LHS, Value *RHS,
626626
ICmpInst::Predicate Cond,
627627
const DataLayout &DL,
628628
InstCombiner &IC) {
629-
// FIXME: Support vector of pointers.
630-
if (GEPLHS->getType()->isVectorTy())
629+
if (ICmpInst::isSigned(Cond))
631630
return nullptr;
632631

633-
if (!GEPLHS->hasAllConstantIndices())
632+
// FIXME: Support vector of pointers.
633+
if (!LHS->getType()->isPointerTy())
634634
return nullptr;
635635

636-
APInt Offset(DL.getIndexTypeSizeInBits(GEPLHS->getType()), 0);
636+
APInt Offset(DL.getIndexTypeSizeInBits(LHS->getType()), 0);
637637
Value *PtrBase =
638-
GEPLHS->stripAndAccumulateConstantOffsets(DL, Offset,
639-
/*AllowNonInbounds*/ false);
638+
LHS->stripAndAccumulateConstantOffsets(DL, Offset,
639+
/*AllowNonInbounds*/ false);
640640

641641
// Bail if we looked through addrspacecast.
642-
if (PtrBase->getType() != GEPLHS->getType())
642+
if (PtrBase->getType() != LHS->getType())
643643
return nullptr;
644644

645645
// The set of nodes that will take part in this transformation.
@@ -771,10 +771,7 @@ Instruction *InstCombinerImpl::foldGEPICmp(GEPOperator *GEPLHS, Value *RHS,
771771
return replaceInstUsesWith(I, Cmp);
772772
}
773773

774-
// Otherwise, the base pointers are different and the indices are
775-
// different. Try convert this to an indexed compare by looking through
776-
// PHIs/casts.
777-
return transformToIndexedCompare(GEPLHS, RHS, Cond, DL, *this);
774+
return nullptr;
778775
}
779776

780777
bool GEPsInBounds = GEPLHS->isInBounds() && GEPRHS->isInBounds();
@@ -841,9 +838,7 @@ Instruction *InstCombinerImpl::foldGEPICmp(GEPOperator *GEPLHS, Value *RHS,
841838
}
842839
}
843840

844-
// Try convert this to an indexed compare by looking through PHIs/casts as a
845-
// last resort.
846-
return transformToIndexedCompare(GEPLHS, RHS, Cond, DL, *this);
841+
return nullptr;
847842
}
848843

849844
bool InstCombinerImpl::foldAllocaCmp(AllocaInst *Alloca) {
@@ -6909,6 +6904,10 @@ Instruction *InstCombinerImpl::foldICmpCommutative(ICmpInst::Predicate Pred,
69096904
if (Instruction *NI = foldGEPICmp(GEP, Op1, Pred, CxtI))
69106905
return NI;
69116906

6907+
if (Instruction *Res =
6908+
transformToIndexedCompare(Op0, Op1, Pred, getDataLayout(), *this))
6909+
return Res;
6910+
69126911
if (auto *SI = dyn_cast<SelectInst>(Op0))
69136912
if (Instruction *NI = foldSelectICmp(Pred, SI, Op1, CxtI))
69146913
return NI;

llvm/test/Analysis/ValueTracking/phi-known-bits.ll

Lines changed: 23 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -622,16 +622,16 @@ while.end.i:
622622
define i1 @recursiveGEP_withPtrSub1_notKnownNonEqual2(ptr %val1) {
623623
; CHECK-LABEL: @recursiveGEP_withPtrSub1_notKnownNonEqual2(
624624
; CHECK-NEXT: entry:
625-
; CHECK-NEXT: [[TEST_VAL1:%.*]] = getelementptr inbounds i8, ptr [[VAL1:%.*]], i64 -1
626625
; CHECK-NEXT: br label [[WHILE_COND_I:%.*]]
627626
; CHECK: while.cond.i:
628-
; CHECK-NEXT: [[A_PN_I:%.*]] = phi ptr [ [[TEST_0_I:%.*]], [[WHILE_COND_I]] ], [ [[TEST_VAL1]], [[ENTRY:%.*]] ]
629-
; CHECK-NEXT: [[TEST_0_I]] = getelementptr inbounds i8, ptr [[A_PN_I]], i64 1
630-
; CHECK-NEXT: [[TMP0:%.*]] = load i8, ptr [[TEST_0_I]], align 2
627+
; CHECK-NEXT: [[A_PN_I_IDX:%.*]] = phi i64 [ [[A_PN_I_ADD:%.*]], [[WHILE_COND_I]] ], [ -1, [[ENTRY:%.*]] ]
628+
; CHECK-NEXT: [[A_PN_I_ADD]] = add nsw i64 [[A_PN_I_IDX]], 1
629+
; CHECK-NEXT: [[TEST_0_I_PTR:%.*]] = getelementptr inbounds i8, ptr [[VAL1:%.*]], i64 [[A_PN_I_ADD]]
630+
; CHECK-NEXT: [[TMP0:%.*]] = load i8, ptr [[TEST_0_I_PTR]], align 2
631631
; CHECK-NEXT: [[CMP3_NOT_I:%.*]] = icmp eq i8 [[TMP0]], 0
632632
; CHECK-NEXT: br i1 [[CMP3_NOT_I]], label [[WHILE_END_I:%.*]], label [[WHILE_COND_I]]
633633
; CHECK: while.end.i:
634-
; CHECK-NEXT: [[BOOL:%.*]] = icmp eq ptr [[TEST_0_I]], [[VAL1]]
634+
; CHECK-NEXT: [[BOOL:%.*]] = icmp eq i64 [[A_PN_I_ADD]], 0
635635
; CHECK-NEXT: ret i1 [[BOOL]]
636636
;
637637
entry:
@@ -656,16 +656,16 @@ while.end.i:
656656
define i1 @recursiveGEP_withPtrSub1_notKnownNonEqual3(ptr %val1) {
657657
; CHECK-LABEL: @recursiveGEP_withPtrSub1_notKnownNonEqual3(
658658
; CHECK-NEXT: entry:
659-
; CHECK-NEXT: [[TEST_VAL1:%.*]] = getelementptr inbounds i8, ptr [[VAL1:%.*]], i64 5
660659
; CHECK-NEXT: br label [[WHILE_COND_I:%.*]]
661660
; CHECK: while.cond.i:
662-
; CHECK-NEXT: [[A_PN_I:%.*]] = phi ptr [ [[TEST_0_I:%.*]], [[WHILE_COND_I]] ], [ [[TEST_VAL1]], [[ENTRY:%.*]] ]
663-
; CHECK-NEXT: [[TEST_0_I]] = getelementptr inbounds i8, ptr [[A_PN_I]], i64 -1
664-
; CHECK-NEXT: [[TMP0:%.*]] = load i8, ptr [[TEST_0_I]], align 2
661+
; CHECK-NEXT: [[A_PN_I_IDX:%.*]] = phi i64 [ [[A_PN_I_ADD:%.*]], [[WHILE_COND_I]] ], [ 5, [[ENTRY:%.*]] ]
662+
; CHECK-NEXT: [[A_PN_I_ADD]] = add nsw i64 [[A_PN_I_IDX]], -1
663+
; CHECK-NEXT: [[TEST_0_I_PTR:%.*]] = getelementptr inbounds i8, ptr [[VAL1:%.*]], i64 [[A_PN_I_ADD]]
664+
; CHECK-NEXT: [[TMP0:%.*]] = load i8, ptr [[TEST_0_I_PTR]], align 2
665665
; CHECK-NEXT: [[CMP3_NOT_I:%.*]] = icmp eq i8 [[TMP0]], 0
666666
; CHECK-NEXT: br i1 [[CMP3_NOT_I]], label [[WHILE_END_I:%.*]], label [[WHILE_COND_I]]
667667
; CHECK: while.end.i:
668-
; CHECK-NEXT: [[BOOL:%.*]] = icmp eq ptr [[TEST_0_I]], [[VAL1]]
668+
; CHECK-NEXT: [[BOOL:%.*]] = icmp eq i64 [[A_PN_I_ADD]], 0
669669
; CHECK-NEXT: ret i1 [[BOOL]]
670670
;
671671
entry:
@@ -692,13 +692,14 @@ define i1 @recursiveGEP_withPtrSub_maybeZero(ptr %val1) {
692692
; CHECK-NEXT: entry:
693693
; CHECK-NEXT: br label [[WHILE_COND_I:%.*]]
694694
; CHECK: while.cond.i:
695-
; CHECK-NEXT: [[A_PN_I:%.*]] = phi ptr [ [[TEST_0_I:%.*]], [[WHILE_COND_I]] ], [ [[VAL1:%.*]], [[ENTRY:%.*]] ]
696-
; CHECK-NEXT: [[TMP0:%.*]] = load i8, ptr [[A_PN_I]], align 2
697-
; CHECK-NEXT: [[TEST_0_I]] = getelementptr inbounds i8, ptr [[A_PN_I]], i64 1
695+
; CHECK-NEXT: [[A_PN_I_IDX:%.*]] = phi i64 [ [[A_PN_I_ADD:%.*]], [[WHILE_COND_I]] ], [ 0, [[ENTRY:%.*]] ]
696+
; CHECK-NEXT: [[A_PN_I_PTR:%.*]] = getelementptr inbounds i8, ptr [[VAL1:%.*]], i64 [[A_PN_I_IDX]]
697+
; CHECK-NEXT: [[TMP0:%.*]] = load i8, ptr [[A_PN_I_PTR]], align 2
698+
; CHECK-NEXT: [[A_PN_I_ADD]] = add nuw nsw i64 [[A_PN_I_IDX]], 1
698699
; CHECK-NEXT: [[CMP3_NOT_I:%.*]] = icmp eq i8 [[TMP0]], 0
699700
; CHECK-NEXT: br i1 [[CMP3_NOT_I]], label [[WHILE_END_I:%.*]], label [[WHILE_COND_I]]
700701
; CHECK: while.end.i:
701-
; CHECK-NEXT: [[BOOL:%.*]] = icmp eq ptr [[A_PN_I]], [[VAL1]]
702+
; CHECK-NEXT: [[BOOL:%.*]] = icmp eq i64 [[A_PN_I_IDX]], 0
702703
; CHECK-NEXT: ret i1 [[BOOL]]
703704
;
704705
entry:
@@ -963,13 +964,16 @@ define i1 @recursiveGEP_withPtrSub_scalableGEP_inbounds(ptr %val1) {
963964
; CHECK-NEXT: entry:
964965
; CHECK-NEXT: br label [[WHILE_COND_I:%.*]]
965966
; CHECK: while.cond.i:
966-
; CHECK-NEXT: [[A_PN_I:%.*]] = phi ptr [ [[TEST_0_I:%.*]], [[WHILE_COND_I]] ], [ [[VAL1:%.*]], [[ENTRY:%.*]] ]
967-
; CHECK-NEXT: [[TEST_0_I]] = getelementptr inbounds <vscale x 16 x i8>, ptr [[A_PN_I]], i64 1
968-
; CHECK-NEXT: [[TMP0:%.*]] = load i8, ptr [[TEST_0_I]], align 1
969-
; CHECK-NEXT: [[CMP3_NOT_I:%.*]] = icmp eq i8 [[TMP0]], 0
967+
; CHECK-NEXT: [[A_PN_I_IDX:%.*]] = phi i64 [ [[A_PN_I_IDX1:%.*]], [[WHILE_COND_I]] ], [ 0, [[ENTRY:%.*]] ]
968+
; CHECK-NEXT: [[TMP0:%.*]] = call i64 @llvm.vscale.i64()
969+
; CHECK-NEXT: [[TMP1:%.*]] = shl i64 [[TMP0]], 4
970+
; CHECK-NEXT: [[A_PN_I_IDX1]] = add i64 [[A_PN_I_IDX]], [[TMP1]]
971+
; CHECK-NEXT: [[TEST_0_I_PTR:%.*]] = getelementptr inbounds i8, ptr [[VAL1:%.*]], i64 [[A_PN_I_IDX1]]
972+
; CHECK-NEXT: [[TMP2:%.*]] = load i8, ptr [[TEST_0_I_PTR]], align 1
973+
; CHECK-NEXT: [[CMP3_NOT_I:%.*]] = icmp eq i8 [[TMP2]], 0
970974
; CHECK-NEXT: br i1 [[CMP3_NOT_I]], label [[WHILE_END_I:%.*]], label [[WHILE_COND_I]]
971975
; CHECK: while.end.i:
972-
; CHECK-NEXT: [[BOOL:%.*]] = icmp eq ptr [[TEST_0_I]], [[VAL1]]
976+
; CHECK-NEXT: [[BOOL:%.*]] = icmp eq i64 [[A_PN_I_IDX1]], 0
973977
; CHECK-NEXT: ret i1 [[BOOL]]
974978
;
975979
entry:

llvm/test/Transforms/InstCombine/getelementptr.ll

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -624,15 +624,15 @@ define i32 @test28() nounwind {
624624
; CHECK-NEXT: entry:
625625
; CHECK-NEXT: [[ORIENTATIONS:%.*]] = alloca [1 x [1 x %struct.x]], align 8
626626
; CHECK-NEXT: [[T3:%.*]] = call i32 @puts(ptr noundef nonnull dereferenceable(1) @.str) #[[ATTR0]]
627-
; CHECK-NEXT: [[T45:%.*]] = getelementptr inbounds i8, ptr [[ORIENTATIONS]], i64 1
628627
; CHECK-NEXT: br label [[BB10:%.*]]
629628
; CHECK: bb10:
630629
; CHECK-NEXT: [[INDVAR:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[INDVAR_NEXT:%.*]], [[BB10]] ]
631630
; CHECK-NEXT: [[T12_REC:%.*]] = xor i32 [[INDVAR]], -1
632631
; CHECK-NEXT: [[TMP0:%.*]] = sext i32 [[T12_REC]] to i64
633-
; CHECK-NEXT: [[T12:%.*]] = getelementptr inbounds [[STRUCT_X:%.*]], ptr [[T45]], i64 [[TMP0]]
634-
; CHECK-NEXT: [[T16:%.*]] = call i32 (ptr, ...) @printf(ptr noundef nonnull dereferenceable(1) @.str1, ptr nonnull [[T12]]) #[[ATTR0]]
635-
; CHECK-NEXT: [[T84:%.*]] = icmp eq ptr [[T12]], [[ORIENTATIONS]]
632+
; CHECK-NEXT: [[TMP1:%.*]] = getelementptr i8, ptr [[ORIENTATIONS]], i64 [[TMP0]]
633+
; CHECK-NEXT: [[T12_PTR:%.*]] = getelementptr i8, ptr [[TMP1]], i64 1
634+
; CHECK-NEXT: [[T16:%.*]] = call i32 (ptr, ...) @printf(ptr noundef nonnull dereferenceable(1) @.str1, ptr nonnull [[T12_PTR]]) #[[ATTR0]]
635+
; CHECK-NEXT: [[T84:%.*]] = icmp eq i32 [[INDVAR]], 0
636636
; CHECK-NEXT: [[INDVAR_NEXT]] = add i32 [[INDVAR]], 1
637637
; CHECK-NEXT: br i1 [[T84]], label [[BB17:%.*]], label [[BB10]]
638638
; CHECK: bb17:

llvm/test/Transforms/InstCombine/pr39908.ll

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,7 @@ target datalayout = "p:32:32"
77

88
define i1 @test(ptr %p, i32 %n) {
99
; CHECK-LABEL: @test(
10-
; CHECK-NEXT: [[END:%.*]] = getelementptr inbounds [0 x %S], ptr [[P:%.*]], i32 0, i32 [[N:%.*]], i32 0, i32 0
11-
; CHECK-NEXT: [[LAST:%.*]] = getelementptr inbounds i8, ptr [[END]], i32 -8
12-
; CHECK-NEXT: [[CMP:%.*]] = icmp eq ptr [[LAST]], [[P]]
10+
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[N:%.*]], 1
1311
; CHECK-NEXT: ret i1 [[CMP]]
1412
;
1513
%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) {
2220
define i1 @test64(ptr %p, i64 %n) {
2321
; CHECK-LABEL: @test64(
2422
; CHECK-NEXT: [[TMP1:%.*]] = trunc i64 [[N:%.*]] to i32
25-
; CHECK-NEXT: [[END:%.*]] = getelementptr inbounds [0 x %S], ptr [[P:%.*]], i32 0, i32 [[TMP1]], i32 0, i32 0
26-
; CHECK-NEXT: [[LAST:%.*]] = getelementptr inbounds i8, ptr [[END]], i32 -8
27-
; CHECK-NEXT: [[CMP:%.*]] = icmp eq ptr [[LAST]], [[P]]
23+
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[TMP1]], 1
2824
; CHECK-NEXT: ret i1 [[CMP]]
2925
;
3026
%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) {
3733
define i1 @test64_overflow(ptr %p, i64 %n) {
3834
; CHECK-LABEL: @test64_overflow(
3935
; CHECK-NEXT: [[TMP1:%.*]] = trunc i64 [[N:%.*]] to i32
40-
; CHECK-NEXT: [[END:%.*]] = getelementptr inbounds [0 x %S], ptr [[P:%.*]], i32 0, i32 [[TMP1]], i32 0, i32 0
41-
; CHECK-NEXT: [[LAST:%.*]] = getelementptr inbounds i8, ptr [[END]], i32 -8
42-
; CHECK-NEXT: [[CMP:%.*]] = icmp eq ptr [[LAST]], [[P]]
36+
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[TMP1]], 1
4337
; CHECK-NEXT: ret i1 [[CMP]]
4438
;
4539
%end = getelementptr inbounds [0 x %S], ptr %p, i64 0, i64 %n, i32 0, i64 8589934592

llvm/test/Transforms/PhaseOrdering/loop-access-checks.ll

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ define void @test_fill_with_foreach([2 x i64] %elems.coerce) {
2424
; CHECK-NEXT: [[ELEMS_COERCE_FCA_0_EXTRACT:%.*]] = extractvalue [2 x i64] [[ELEMS_COERCE]], 0
2525
; CHECK-NEXT: [[TMP0:%.*]] = inttoptr i64 [[ELEMS_COERCE_FCA_0_EXTRACT]] to ptr
2626
; CHECK-NEXT: [[ELEMS_COERCE_FCA_1_EXTRACT:%.*]] = extractvalue [2 x i64] [[ELEMS_COERCE]], 1
27-
; CHECK-NEXT: [[ADD_PTR_I:%.*]] = getelementptr inbounds i32, ptr [[TMP0]], i64 [[ELEMS_COERCE_FCA_1_EXTRACT]]
27+
; CHECK-NEXT: [[ADD_PTR_I_IDX:%.*]] = shl nsw i64 [[ELEMS_COERCE_FCA_1_EXTRACT]], 2
2828
; CHECK-NEXT: [[CMP_NOT_I_I_I_I:%.*]] = icmp slt i64 [[ELEMS_COERCE_FCA_1_EXTRACT]], 0
2929
; CHECK-NEXT: br i1 [[CMP_NOT_I_I_I_I]], label [[ERROR:%.*]], label [[FOR_COND_PREHEADER_SPLIT:%.*]]
3030
; CHECK: for.cond.preheader.split:
@@ -36,10 +36,11 @@ define void @test_fill_with_foreach([2 x i64] %elems.coerce) {
3636
; CHECK-NEXT: tail call void @error()
3737
; CHECK-NEXT: br label [[COMMON_RET]]
3838
; CHECK: for.body:
39-
; CHECK-NEXT: [[__BEGIN1_SROA_0_03:%.*]] = phi ptr [ [[INCDEC_PTR_I:%.*]], [[FOR_BODY]] ], [ [[TMP0]], [[FOR_COND_PREHEADER_SPLIT]] ]
40-
; CHECK-NEXT: tail call void @use(ptr noundef nonnull align 4 dereferenceable(4) [[__BEGIN1_SROA_0_03]])
41-
; CHECK-NEXT: [[INCDEC_PTR_I]] = getelementptr inbounds i8, ptr [[__BEGIN1_SROA_0_03]], i64 4
42-
; CHECK-NEXT: [[CMP_I_NOT:%.*]] = icmp eq ptr [[INCDEC_PTR_I]], [[ADD_PTR_I]]
39+
; CHECK-NEXT: [[__BEGIN1_SROA_0_0_IDX3:%.*]] = phi i64 [ [[__BEGIN1_SROA_0_0_ADD:%.*]], [[FOR_BODY]] ], [ 0, [[FOR_COND_PREHEADER_SPLIT]] ]
40+
; CHECK-NEXT: [[__BEGIN1_SROA_0_0_PTR4:%.*]] = getelementptr inbounds i8, ptr [[TMP0]], i64 [[__BEGIN1_SROA_0_0_IDX3]]
41+
; CHECK-NEXT: tail call void @use(ptr noundef nonnull align 4 dereferenceable(4) [[__BEGIN1_SROA_0_0_PTR4]])
42+
; CHECK-NEXT: [[__BEGIN1_SROA_0_0_ADD]] = add nuw nsw i64 [[__BEGIN1_SROA_0_0_IDX3]], 4
43+
; CHECK-NEXT: [[CMP_I_NOT:%.*]] = icmp eq i64 [[__BEGIN1_SROA_0_0_ADD]], [[ADD_PTR_I_IDX]]
4344
; CHECK-NEXT: br i1 [[CMP_I_NOT]], label [[COMMON_RET]], label [[FOR_BODY]]
4445
;
4546
entry:

0 commit comments

Comments
 (0)