Skip to content

Commit f0f3194

Browse files
authored
[InstCombine] Fold icmp of gep chains (#146714)
This extends #144065 to the general case of an icmp between two GEP chains that have a common base.
1 parent 97eec75 commit f0f3194

File tree

2 files changed

+155
-13
lines changed

2 files changed

+155
-13
lines changed

llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -755,8 +755,7 @@ Instruction *InstCombinerImpl::foldGEPICmp(GEPOperator *GEPLHS, Value *RHS,
755755

756756
// If the base pointers are different, but the indices are the same, just
757757
// compare the base pointer.
758-
Value *PtrBase = GEPLHS->getOperand(0);
759-
if (PtrBase != GEPRHS->getOperand(0)) {
758+
if (GEPLHS->getOperand(0) != GEPRHS->getOperand(0)) {
760759
bool IndicesTheSame =
761760
GEPLHS->getNumOperands() == GEPRHS->getNumOperands() &&
762761
GEPLHS->getPointerOperand()->getType() ==
@@ -782,7 +781,7 @@ Instruction *InstCombinerImpl::foldGEPICmp(GEPOperator *GEPLHS, Value *RHS,
782781
if (GEPLHS->isInBounds() && GEPRHS->isInBounds() &&
783782
(GEPLHS->hasAllConstantIndices() || GEPLHS->hasOneUse()) &&
784783
(GEPRHS->hasAllConstantIndices() || GEPRHS->hasOneUse()) &&
785-
PtrBase->stripPointerCasts() ==
784+
GEPLHS->getOperand(0)->stripPointerCasts() ==
786785
GEPRHS->getOperand(0)->stripPointerCasts() &&
787786
!GEPLHS->getType()->isVectorTy()) {
788787
Value *LOffset = EmitGEPOffset(GEPLHS);
@@ -805,14 +804,10 @@ Instruction *InstCombinerImpl::foldGEPICmp(GEPOperator *GEPLHS, Value *RHS,
805804
LOffset, ROffset);
806805
return replaceInstUsesWith(I, Cmp);
807806
}
808-
809-
// Otherwise, the base pointers are different and the indices are
810-
// different. Try convert this to an indexed compare by looking through
811-
// PHIs/casts.
812-
return transformToIndexedCompare(GEPLHS, RHS, Cond, DL, *this);
813807
}
814808

815-
if (GEPLHS->getNumOperands() == GEPRHS->getNumOperands() &&
809+
if (GEPLHS->getOperand(0) == GEPRHS->getOperand(0) &&
810+
GEPLHS->getNumOperands() == GEPRHS->getNumOperands() &&
816811
GEPLHS->getSourceElementType() == GEPRHS->getSourceElementType()) {
817812
// If the GEPs only differ by one index, compare it.
818813
unsigned NumDifferences = 0; // Keep track of # differences.
@@ -849,11 +844,14 @@ Instruction *InstCombinerImpl::foldGEPICmp(GEPOperator *GEPLHS, Value *RHS,
849844
}
850845
}
851846

852-
if (CanFold(NW)) {
847+
if (Base.Ptr && CanFold(Base.LHSNW & Base.RHSNW) && !Base.isExpensive()) {
853848
// ((gep Ptr, OFFSET1) cmp (gep Ptr, OFFSET2) ---> (OFFSET1 cmp OFFSET2)
854-
Value *L = EmitGEPOffset(GEPLHS, /*RewriteGEP=*/true);
855-
Value *R = EmitGEPOffset(GEPRHS, /*RewriteGEP=*/true);
856-
return NewICmp(NW, L, R);
849+
Type *IdxTy = DL.getIndexType(GEPLHS->getType());
850+
Value *L =
851+
EmitGEPOffsets(Base.LHSGEPs, Base.LHSNW, IdxTy, /*RewriteGEP=*/true);
852+
Value *R =
853+
EmitGEPOffsets(Base.RHSGEPs, Base.RHSNW, IdxTy, /*RewriteGEP=*/true);
854+
return NewICmp(Base.LHSNW & Base.RHSNW, L, R);
857855
}
858856
}
859857

llvm/test/Transforms/InstCombine/icmp-gep.ll

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -981,3 +981,147 @@ define i1 @gep_multiple_multi_use_above_limit(ptr %base, i64 %idx1, i64 %idx2, i
981981
%cmp = icmp eq ptr %gep4, %base
982982
ret i1 %cmp
983983
}
984+
985+
define i1 @gep_gep_multiple_eq(ptr %base, i64 %idx1, i64 %idx2, i64 %idx3, i64 %idx4) {
986+
; CHECK-LABEL: @gep_gep_multiple_eq(
987+
; CHECK-NEXT: [[GEP1_IDX1:%.*]] = add i64 [[IDX1:%.*]], [[IDX2:%.*]]
988+
; CHECK-NEXT: [[GEP3_IDX2:%.*]] = add i64 [[IDX3:%.*]], [[IDX4:%.*]]
989+
; CHECK-NEXT: [[CMP_UNSHIFTED:%.*]] = xor i64 [[GEP1_IDX1]], [[GEP3_IDX2]]
990+
; CHECK-NEXT: [[CMP_MASK:%.*]] = and i64 [[CMP_UNSHIFTED]], 4611686018427387903
991+
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i64 [[CMP_MASK]], 0
992+
; CHECK-NEXT: ret i1 [[CMP]]
993+
;
994+
%gep1 = getelementptr i32, ptr %base, i64 %idx1
995+
%gep2 = getelementptr i32, ptr %gep1, i64 %idx2
996+
%gep3 = getelementptr i32, ptr %base, i64 %idx3
997+
%gep4 = getelementptr i32, ptr %gep3, i64 %idx4
998+
%cmp = icmp eq ptr %gep2, %gep4
999+
ret i1 %cmp
1000+
}
1001+
1002+
define i1 @gep_gep_multiple_eq_nuw(ptr %base, i64 %idx1, i64 %idx2, i64 %idx3, i64 %idx4) {
1003+
; CHECK-LABEL: @gep_gep_multiple_eq_nuw(
1004+
; CHECK-NEXT: [[GEP1_IDX1:%.*]] = add i64 [[IDX1:%.*]], [[IDX2:%.*]]
1005+
; CHECK-NEXT: [[GEP3_IDX2:%.*]] = add i64 [[IDX3:%.*]], [[IDX4:%.*]]
1006+
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i64 [[GEP1_IDX1]], [[GEP3_IDX2]]
1007+
; CHECK-NEXT: ret i1 [[CMP]]
1008+
;
1009+
%gep1 = getelementptr nuw i32, ptr %base, i64 %idx1
1010+
%gep2 = getelementptr nuw i32, ptr %gep1, i64 %idx2
1011+
%gep3 = getelementptr nuw i32, ptr %base, i64 %idx3
1012+
%gep4 = getelementptr nuw i32, ptr %gep3, i64 %idx4
1013+
%cmp = icmp eq ptr %gep2, %gep4
1014+
ret i1 %cmp
1015+
}
1016+
1017+
define i1 @gep_gep_multiple_eq_nuw_different_scales(ptr %base, i64 %idx1, i64 %idx2, i64 %idx3, i64 %idx4) {
1018+
; CHECK-LABEL: @gep_gep_multiple_eq_nuw_different_scales(
1019+
; CHECK-NEXT: [[GEP1_IDX:%.*]] = shl nuw i64 [[IDX1:%.*]], 2
1020+
; CHECK-NEXT: [[GEP2_IDX:%.*]] = shl nuw i64 [[IDX2:%.*]], 3
1021+
; CHECK-NEXT: [[TMP1:%.*]] = add nuw i64 [[GEP1_IDX]], [[GEP2_IDX]]
1022+
; CHECK-NEXT: [[GEP3_IDX:%.*]] = shl nuw i64 [[IDX3:%.*]], 2
1023+
; CHECK-NEXT: [[GEP4_IDX:%.*]] = shl nuw i64 [[IDX4:%.*]], 3
1024+
; CHECK-NEXT: [[TMP2:%.*]] = add nuw i64 [[GEP3_IDX]], [[GEP4_IDX]]
1025+
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i64 [[TMP1]], [[TMP2]]
1026+
; CHECK-NEXT: ret i1 [[CMP]]
1027+
;
1028+
%gep1 = getelementptr nuw i32, ptr %base, i64 %idx1
1029+
%gep2 = getelementptr nuw i64, ptr %gep1, i64 %idx2
1030+
%gep3 = getelementptr nuw i32, ptr %base, i64 %idx3
1031+
%gep4 = getelementptr nuw i64, ptr %gep3, i64 %idx4
1032+
%cmp = icmp eq ptr %gep2, %gep4
1033+
ret i1 %cmp
1034+
}
1035+
1036+
define i1 @gep_gep_multiple_eq_partial_nuw_different_scales(ptr %base, i64 %idx1, i64 %idx2, i64 %idx3, i64 %idx4) {
1037+
; CHECK-LABEL: @gep_gep_multiple_eq_partial_nuw_different_scales(
1038+
; CHECK-NEXT: [[GEP1_IDX:%.*]] = shl nuw i64 [[IDX1:%.*]], 2
1039+
; CHECK-NEXT: [[GEP2_IDX:%.*]] = shl nuw i64 [[IDX2:%.*]], 3
1040+
; CHECK-NEXT: [[TMP1:%.*]] = add nuw i64 [[GEP1_IDX]], [[GEP2_IDX]]
1041+
; CHECK-NEXT: [[GEP3_IDX:%.*]] = shl nuw i64 [[IDX3:%.*]], 2
1042+
; CHECK-NEXT: [[GEP4_IDX:%.*]] = shl i64 [[IDX4:%.*]], 3
1043+
; CHECK-NEXT: [[TMP2:%.*]] = add i64 [[GEP3_IDX]], [[GEP4_IDX]]
1044+
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i64 [[TMP1]], [[TMP2]]
1045+
; CHECK-NEXT: ret i1 [[CMP]]
1046+
;
1047+
%gep1 = getelementptr nuw i32, ptr %base, i64 %idx1
1048+
%gep2 = getelementptr nuw i64, ptr %gep1, i64 %idx2
1049+
%gep3 = getelementptr nuw i32, ptr %base, i64 %idx3
1050+
%gep4 = getelementptr i64, ptr %gep3, i64 %idx4
1051+
%cmp = icmp eq ptr %gep2, %gep4
1052+
ret i1 %cmp
1053+
}
1054+
1055+
define i1 @gep_gep_multiple_eq_partial_inbounds_different_scales(ptr %base, i64 %idx1, i64 %idx2, i64 %idx3, i64 %idx4) {
1056+
; CHECK-LABEL: @gep_gep_multiple_eq_partial_inbounds_different_scales(
1057+
; CHECK-NEXT: [[GEP1_IDX:%.*]] = shl nsw i64 [[IDX1:%.*]], 2
1058+
; CHECK-NEXT: [[GEP2_IDX:%.*]] = shl nsw i64 [[IDX2:%.*]], 3
1059+
; CHECK-NEXT: [[TMP1:%.*]] = add nsw i64 [[GEP1_IDX]], [[GEP2_IDX]]
1060+
; CHECK-NEXT: [[GEP3_IDX:%.*]] = shl nsw i64 [[IDX3:%.*]], 2
1061+
; CHECK-NEXT: [[GEP4_IDX:%.*]] = shl i64 [[IDX4:%.*]], 3
1062+
; CHECK-NEXT: [[TMP2:%.*]] = add i64 [[GEP3_IDX]], [[GEP4_IDX]]
1063+
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i64 [[TMP1]], [[TMP2]]
1064+
; CHECK-NEXT: ret i1 [[CMP]]
1065+
;
1066+
%gep1 = getelementptr inbounds i32, ptr %base, i64 %idx1
1067+
%gep2 = getelementptr inbounds i64, ptr %gep1, i64 %idx2
1068+
%gep3 = getelementptr inbounds i32, ptr %base, i64 %idx3
1069+
%gep4 = getelementptr i64, ptr %gep3, i64 %idx4
1070+
%cmp = icmp eq ptr %gep2, %gep4
1071+
ret i1 %cmp
1072+
}
1073+
1074+
define i1 @gep_gep_multiple_ult_nuw(ptr %base, i64 %idx1, i64 %idx2, i64 %idx3, i64 %idx4) {
1075+
; CHECK-LABEL: @gep_gep_multiple_ult_nuw(
1076+
; CHECK-NEXT: [[GEP1_IDX1:%.*]] = add i64 [[IDX1:%.*]], [[IDX2:%.*]]
1077+
; CHECK-NEXT: [[GEP3_IDX2:%.*]] = add i64 [[IDX3:%.*]], [[IDX4:%.*]]
1078+
; CHECK-NEXT: [[CMP:%.*]] = icmp ult i64 [[GEP1_IDX1]], [[GEP3_IDX2]]
1079+
; CHECK-NEXT: ret i1 [[CMP]]
1080+
;
1081+
%gep1 = getelementptr nuw i32, ptr %base, i64 %idx1
1082+
%gep2 = getelementptr nuw i32, ptr %gep1, i64 %idx2
1083+
%gep3 = getelementptr nuw i32, ptr %base, i64 %idx3
1084+
%gep4 = getelementptr nuw i32, ptr %gep3, i64 %idx4
1085+
%cmp = icmp ult ptr %gep2, %gep4
1086+
ret i1 %cmp
1087+
}
1088+
1089+
define i1 @gep_gep_multiple_ult_missing_nuw(ptr %base, i64 %idx1, i64 %idx2, i64 %idx3, i64 %idx4) {
1090+
; CHECK-LABEL: @gep_gep_multiple_ult_missing_nuw(
1091+
; CHECK-NEXT: [[GEP1:%.*]] = getelementptr nuw i32, ptr [[BASE:%.*]], i64 [[IDX1:%.*]]
1092+
; CHECK-NEXT: [[GEP2:%.*]] = getelementptr nuw i32, ptr [[GEP1]], i64 [[IDX2:%.*]]
1093+
; CHECK-NEXT: [[GEP3:%.*]] = getelementptr nuw i32, ptr [[BASE]], i64 [[IDX3:%.*]]
1094+
; CHECK-NEXT: [[GEP4:%.*]] = getelementptr i32, ptr [[GEP3]], i64 [[IDX4:%.*]]
1095+
; CHECK-NEXT: [[CMP:%.*]] = icmp ult ptr [[GEP2]], [[GEP4]]
1096+
; CHECK-NEXT: ret i1 [[CMP]]
1097+
;
1098+
%gep1 = getelementptr nuw i32, ptr %base, i64 %idx1
1099+
%gep2 = getelementptr nuw i32, ptr %gep1, i64 %idx2
1100+
%gep3 = getelementptr nuw i32, ptr %base, i64 %idx3
1101+
%gep4 = getelementptr i32, ptr %gep3, i64 %idx4
1102+
%cmp = icmp ult ptr %gep2, %gep4
1103+
ret i1 %cmp
1104+
}
1105+
1106+
define i1 @gep_gep_multiple_ult_nuw_multi_use(ptr %base, i64 %idx1, i64 %idx2, i64 %idx3, i64 %idx4) {
1107+
; CHECK-LABEL: @gep_gep_multiple_ult_nuw_multi_use(
1108+
; CHECK-NEXT: [[IDX3:%.*]] = add i64 [[IDX1:%.*]], [[IDX2:%.*]]
1109+
; CHECK-NEXT: [[GEP3_IDX:%.*]] = shl nuw i64 [[IDX3]], 2
1110+
; CHECK-NEXT: [[GEP3:%.*]] = getelementptr nuw i8, ptr [[BASE:%.*]], i64 [[GEP3_IDX]]
1111+
; CHECK-NEXT: [[IDX4:%.*]] = add i64 [[IDX5:%.*]], [[IDX6:%.*]]
1112+
; CHECK-NEXT: [[GEP4_IDX:%.*]] = shl nuw i64 [[IDX4]], 2
1113+
; CHECK-NEXT: [[GEP5:%.*]] = getelementptr nuw i8, ptr [[BASE]], i64 [[GEP4_IDX]]
1114+
; CHECK-NEXT: call void @use(ptr [[GEP3]])
1115+
; CHECK-NEXT: call void @use(ptr [[GEP5]])
1116+
; CHECK-NEXT: [[CMP:%.*]] = icmp ult i64 [[GEP3_IDX]], [[GEP4_IDX]]
1117+
; CHECK-NEXT: ret i1 [[CMP]]
1118+
;
1119+
%gep1 = getelementptr nuw i32, ptr %base, i64 %idx1
1120+
%gep2 = getelementptr nuw i32, ptr %gep1, i64 %idx2
1121+
%gep3 = getelementptr nuw i32, ptr %base, i64 %idx3
1122+
%gep4 = getelementptr nuw i32, ptr %gep3, i64 %idx4
1123+
call void @use(ptr %gep2)
1124+
call void @use(ptr %gep4)
1125+
%cmp = icmp ult ptr %gep2, %gep4
1126+
ret i1 %cmp
1127+
}

0 commit comments

Comments
 (0)