Skip to content

Commit b1b8a38

Browse files
authored
[InstCombine] Remove one-use restriction on icmp of gep fold (llvm#76730)
The fold for icmp (gep (p, i1), gep (p, i2)) to icmp (i1, i2) is currently limited to one of the GEPs either having one use or a constant offset. I believe this is to avoid duplicating complex arithmetic both in the GEP and the offset comparison. This patch instead does the same thing that the indexed compare fold does, which is to rewrite the GEP into i8 form if necessary, so that the offset arithmetic is not repeated after the transform. I ran into this problem in a case where there are multiple conditions on the same pointer, which prevents them from getting folded.
1 parent b5abaea commit b1b8a38

File tree

3 files changed

+35
-16
lines changed

3 files changed

+35
-16
lines changed

llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp

+23-7
Original file line numberDiff line numberDiff line change
@@ -813,14 +813,30 @@ Instruction *InstCombinerImpl::foldGEPICmp(GEPOperator *GEPLHS, Value *RHS,
813813
}
814814
}
815815

816-
// Only lower this if the icmp is the only user of the GEP or if we expect
817-
// the result to fold to a constant!
818-
if ((GEPsInBounds || CmpInst::isEquality(Cond)) &&
819-
(GEPLHS->hasAllConstantIndices() || GEPLHS->hasOneUse()) &&
820-
(GEPRHS->hasAllConstantIndices() || GEPRHS->hasOneUse())) {
816+
if (GEPsInBounds || CmpInst::isEquality(Cond)) {
817+
auto EmitGEPOffsetAndRewrite = [&](GEPOperator *GEP) {
818+
IRBuilderBase::InsertPointGuard Guard(Builder);
819+
auto *Inst = dyn_cast<Instruction>(GEP);
820+
if (Inst)
821+
Builder.SetInsertPoint(Inst);
822+
823+
Value *Offset = EmitGEPOffset(GEP);
824+
// If a non-trivial GEP has other uses, rewrite it to avoid duplicating
825+
// the offset arithmetic.
826+
if (Inst && !GEP->hasOneUse() && !GEP->hasAllConstantIndices() &&
827+
!GEP->getSourceElementType()->isIntegerTy(8)) {
828+
replaceInstUsesWith(*Inst,
829+
Builder.CreateGEP(Builder.getInt8Ty(),
830+
GEP->getPointerOperand(),
831+
Offset, "", GEPsInBounds));
832+
eraseInstFromFunction(*Inst);
833+
}
834+
return Offset;
835+
};
836+
821837
// ((gep Ptr, OFFSET1) cmp (gep Ptr, OFFSET2) ---> (OFFSET1 cmp OFFSET2)
822-
Value *L = EmitGEPOffset(GEPLHS);
823-
Value *R = EmitGEPOffset(GEPRHS);
838+
Value *L = EmitGEPOffsetAndRewrite(GEPLHS);
839+
Value *R = EmitGEPOffsetAndRewrite(GEPRHS);
824840
return new ICmpInst(ICmpInst::getSignedPredicate(Cond), L, R);
825841
}
826842
}

llvm/test/Transforms/InstCombine/icmp-custom-dl.ll

+2-2
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,8 @@ define i1 @test59_as1(ptr addrspace(1) %foo) {
4040
define i1 @test60(ptr %foo, i64 %i, i64 %j) {
4141
; CHECK-LABEL: @test60(
4242
; CHECK-NEXT: [[TMP1:%.*]] = trunc i64 [[I:%.*]] to i32
43-
; CHECK-NEXT: [[TMP2:%.*]] = trunc i64 [[J:%.*]] to i32
4443
; CHECK-NEXT: [[GEP1_IDX:%.*]] = shl nsw i32 [[TMP1]], 2
44+
; CHECK-NEXT: [[TMP2:%.*]] = trunc i64 [[J:%.*]] to i32
4545
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[GEP1_IDX]], [[TMP2]]
4646
; CHECK-NEXT: ret i1 [[CMP]]
4747
;
@@ -54,8 +54,8 @@ define i1 @test60(ptr %foo, i64 %i, i64 %j) {
5454
define i1 @test60_as1(ptr addrspace(1) %foo, i64 %i, i64 %j) {
5555
; CHECK-LABEL: @test60_as1(
5656
; CHECK-NEXT: [[TMP1:%.*]] = trunc i64 [[I:%.*]] to i16
57-
; CHECK-NEXT: [[TMP2:%.*]] = trunc i64 [[J:%.*]] to i16
5857
; CHECK-NEXT: [[GEP1_IDX:%.*]] = shl nsw i16 [[TMP1]], 2
58+
; CHECK-NEXT: [[TMP2:%.*]] = trunc i64 [[J:%.*]] to i16
5959
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i16 [[GEP1_IDX]], [[TMP2]]
6060
; CHECK-NEXT: ret i1 [[CMP]]
6161
;

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

+10-7
Original file line numberDiff line numberDiff line change
@@ -313,8 +313,8 @@ define i1 @test_gep_eq_no_inbounds(ptr %foo, i64 %i, i64 %j) {
313313
define i1 @test60_as1(ptr addrspace(1) %foo, i64 %i, i64 %j) {
314314
; CHECK-LABEL: @test60_as1(
315315
; CHECK-NEXT: [[TMP1:%.*]] = trunc i64 [[I:%.*]] to i16
316-
; CHECK-NEXT: [[TMP2:%.*]] = trunc i64 [[J:%.*]] to i16
317316
; CHECK-NEXT: [[GEP1_IDX:%.*]] = shl nsw i16 [[TMP1]], 2
317+
; CHECK-NEXT: [[TMP2:%.*]] = trunc i64 [[J:%.*]] to i16
318318
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i16 [[GEP1_IDX]], [[TMP2]]
319319
; CHECK-NEXT: ret i1 [[CMP]]
320320
;
@@ -400,11 +400,13 @@ define i1 @test61_as1(ptr addrspace(1) %foo, i16 %i, i16 %j) {
400400

401401
define i1 @test60_extra_use(ptr %foo, i64 %i, i64 %j) {
402402
; CHECK-LABEL: @test60_extra_use(
403-
; CHECK-NEXT: [[GEP1:%.*]] = getelementptr inbounds i32, ptr [[FOO:%.*]], i64 [[I:%.*]]
404-
; CHECK-NEXT: [[GEP2:%.*]] = getelementptr inbounds i16, ptr [[FOO]], i64 [[J:%.*]]
403+
; CHECK-NEXT: [[GEP1_IDX:%.*]] = shl nsw i64 [[I:%.*]], 2
404+
; CHECK-NEXT: [[GEP1:%.*]] = getelementptr inbounds i8, ptr [[FOO:%.*]], i64 [[GEP1_IDX]]
405+
; CHECK-NEXT: [[GEP2_IDX:%.*]] = shl nsw i64 [[J:%.*]], 1
406+
; CHECK-NEXT: [[GEP2:%.*]] = getelementptr inbounds i8, ptr [[FOO]], i64 [[GEP2_IDX]]
405407
; CHECK-NEXT: call void @use(ptr [[GEP1]])
406408
; CHECK-NEXT: call void @use(ptr [[GEP2]])
407-
; CHECK-NEXT: [[CMP:%.*]] = icmp ult ptr [[GEP1]], [[GEP2]]
409+
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i64 [[GEP1_IDX]], [[GEP2_IDX]]
408410
; CHECK-NEXT: ret i1 [[CMP]]
409411
;
410412
%gep1 = getelementptr inbounds i32, ptr %foo, i64 %i
@@ -446,13 +448,14 @@ define i1 @test60_extra_use_const_operands_no_inbounds(ptr %foo, i64 %i, i64 %j)
446448

447449
define void @test60_extra_use_fold(ptr %foo, i64 %start.idx, i64 %end.offset) {
448450
; CHECK-LABEL: @test60_extra_use_fold(
449-
; CHECK-NEXT: [[GEP1:%.*]] = getelementptr inbounds i32, ptr [[FOO:%.*]], i64 [[START_IDX:%.*]]
451+
; CHECK-NEXT: [[GEP1_IDX:%.*]] = shl nsw i64 [[START_IDX:%.*]], 2
452+
; CHECK-NEXT: [[GEP1:%.*]] = getelementptr inbounds i8, ptr [[FOO:%.*]], i64 [[GEP1_IDX]]
450453
; CHECK-NEXT: [[GEP2:%.*]] = getelementptr inbounds i8, ptr [[FOO]], i64 [[END_OFFSET:%.*]]
451454
; CHECK-NEXT: call void @use(ptr [[GEP1]])
452455
; CHECK-NEXT: call void @use(ptr [[GEP2]])
453-
; CHECK-NEXT: [[CMP1:%.*]] = icmp eq ptr [[GEP1]], [[GEP2]]
456+
; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i64 [[GEP1_IDX]], [[END_OFFSET]]
454457
; CHECK-NEXT: call void @use.i1(i1 [[CMP1]])
455-
; CHECK-NEXT: [[CMP2:%.*]] = icmp ult ptr [[GEP1]], [[GEP2]]
458+
; CHECK-NEXT: [[CMP2:%.*]] = icmp slt i64 [[GEP1_IDX]], [[END_OFFSET]]
456459
; CHECK-NEXT: call void @use.i1(i1 [[CMP2]])
457460
; CHECK-NEXT: ret void
458461
;

0 commit comments

Comments
 (0)