Skip to content

Commit f335364

Browse files
authored
[InstCombine] Support gep nuw in icmp folds (#118472)
Unsigned icmp of gep nuw folds to unsigned icmp of offsets. Unsigned icmp of gep nusw nuw folds to unsigned samesign icmp of offsets. Proofs: https://alive2.llvm.org/ce/z/VEwQY8
1 parent 81d82ca commit f335364

File tree

2 files changed

+102
-9
lines changed

2 files changed

+102
-9
lines changed

llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -690,13 +690,32 @@ Instruction *InstCombinerImpl::foldGEPICmp(GEPOperator *GEPLHS, Value *RHS,
690690
if (!isa<GetElementPtrInst>(RHS))
691691
RHS = RHS->stripPointerCasts();
692692

693+
auto CanFold = [Cond](GEPNoWrapFlags NW) {
694+
if (ICmpInst::isEquality(Cond))
695+
return true;
696+
697+
// Unsigned predicates can be folded if the GEPs have *any* nowrap flags.
698+
assert(ICmpInst::isUnsigned(Cond));
699+
return NW != GEPNoWrapFlags::none();
700+
};
701+
702+
auto NewICmp = [Cond](GEPNoWrapFlags NW, Value *Op1, Value *Op2) {
703+
if (!NW.hasNoUnsignedWrap()) {
704+
// Convert signed to unsigned comparison.
705+
return new ICmpInst(ICmpInst::getSignedPredicate(Cond), Op1, Op2);
706+
}
707+
708+
auto *I = new ICmpInst(Cond, Op1, Op2);
709+
I->setSameSign(NW.hasNoUnsignedSignedWrap());
710+
return I;
711+
};
712+
693713
Value *PtrBase = GEPLHS->getOperand(0);
694-
if (PtrBase == RHS &&
695-
(GEPLHS->hasNoUnsignedSignedWrap() || ICmpInst::isEquality(Cond))) {
714+
if (PtrBase == RHS && CanFold(GEPLHS->getNoWrapFlags())) {
696715
// ((gep Ptr, OFFSET) cmp Ptr) ---> (OFFSET cmp 0).
697716
Value *Offset = EmitGEPOffset(GEPLHS);
698-
return new ICmpInst(ICmpInst::getSignedPredicate(Cond), Offset,
699-
Constant::getNullValue(Offset->getType()));
717+
return NewICmp(GEPLHS->getNoWrapFlags(), Offset,
718+
Constant::getNullValue(Offset->getType()));
700719
}
701720

702721
if (GEPLHS->isInBounds() && ICmpInst::isEquality(Cond) &&
@@ -814,19 +833,18 @@ Instruction *InstCombinerImpl::foldGEPICmp(GEPOperator *GEPLHS, Value *RHS,
814833
return replaceInstUsesWith(I, // No comparison is needed here.
815834
ConstantInt::get(I.getType(), ICmpInst::isTrueWhenEqual(Cond)));
816835

817-
else if (NumDifferences == 1 && NW.hasNoUnsignedSignedWrap()) {
836+
else if (NumDifferences == 1 && CanFold(NW)) {
818837
Value *LHSV = GEPLHS->getOperand(DiffOperand);
819838
Value *RHSV = GEPRHS->getOperand(DiffOperand);
820-
// Make sure we do a signed comparison here.
821-
return new ICmpInst(ICmpInst::getSignedPredicate(Cond), LHSV, RHSV);
839+
return NewICmp(NW, LHSV, RHSV);
822840
}
823841
}
824842

825-
if (NW.hasNoUnsignedSignedWrap() || CmpInst::isEquality(Cond)) {
843+
if (CanFold(NW)) {
826844
// ((gep Ptr, OFFSET1) cmp (gep Ptr, OFFSET2) ---> (OFFSET1 cmp OFFSET2)
827845
Value *L = EmitGEPOffset(GEPLHS, /*RewriteGEP=*/true);
828846
Value *R = EmitGEPOffset(GEPRHS, /*RewriteGEP=*/true);
829-
return new ICmpInst(ICmpInst::getSignedPredicate(Cond), L, R);
847+
return NewICmp(NW, L, R);
830848
}
831849
}
832850

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

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,44 @@ define i1 @ult_base_nusw(ptr %x, i64 %y) {
143143
ret i1 %r
144144
}
145145

146+
define i1 @ugt_base_nuw(ptr %x, i64 %y) {
147+
; CHECK-LABEL: @ugt_base_nuw(
148+
; CHECK-NEXT: [[R:%.*]] = icmp ne i64 [[Y:%.*]], 0
149+
; CHECK-NEXT: ret i1 [[R]]
150+
;
151+
%g = getelementptr nuw i8, ptr %x, i64 %y
152+
%r = icmp ugt ptr %g, %x
153+
ret i1 %r
154+
}
155+
156+
define i1 @ugt_base_nusw_nuw(ptr %x, i64 %y) {
157+
; CHECK-LABEL: @ugt_base_nusw_nuw(
158+
; CHECK-NEXT: [[R:%.*]] = icmp ne i64 [[Y:%.*]], 0
159+
; CHECK-NEXT: ret i1 [[R]]
160+
;
161+
%g = getelementptr nusw nuw i8, ptr %x, i64 %y
162+
%r = icmp ugt ptr %g, %x
163+
ret i1 %r
164+
}
165+
166+
define i1 @uge_base_nuw(ptr %x, i64 %y) {
167+
; CHECK-LABEL: @uge_base_nuw(
168+
; CHECK-NEXT: ret i1 true
169+
;
170+
%g = getelementptr nuw i8, ptr %x, i64 %y
171+
%r = icmp uge ptr %g, %x
172+
ret i1 %r
173+
}
174+
175+
define i1 @uge_base_nusw_nuw(ptr %x, i64 %y) {
176+
; CHECK-LABEL: @uge_base_nusw_nuw(
177+
; CHECK-NEXT: ret i1 true
178+
;
179+
%g = getelementptr nusw nuw i8, ptr %x, i64 %y
180+
%r = icmp uge ptr %g, %x
181+
ret i1 %r
182+
}
183+
146184
define i1 @ugt_base_inbounds_commute(i64 %y) {
147185
; CHECK-LABEL: @ugt_base_inbounds_commute(
148186
; CHECK-NEXT: [[X:%.*]] = call ptr @getptr()
@@ -319,6 +357,43 @@ define i1 @test60_nusw_inbounds(ptr %foo, i64 %i, i64 %j) {
319357
ret i1 %cmp
320358
}
321359

360+
define i1 @test60_nuw(ptr %foo, i64 %i, i64 %j) {
361+
; CHECK-LABEL: @test60_nuw(
362+
; CHECK-NEXT: [[GEP1_IDX:%.*]] = shl nuw i64 [[I:%.*]], 2
363+
; CHECK-NEXT: [[CMP:%.*]] = icmp ult i64 [[GEP1_IDX]], [[J:%.*]]
364+
; CHECK-NEXT: ret i1 [[CMP]]
365+
;
366+
%gep1 = getelementptr nuw i32, ptr %foo, i64 %i
367+
%gep2 = getelementptr nuw i8, ptr %foo, i64 %j
368+
%cmp = icmp ult ptr %gep1, %gep2
369+
ret i1 %cmp
370+
}
371+
372+
define i1 @test60_nusw_nuw(ptr %foo, i64 %i, i64 %j) {
373+
; CHECK-LABEL: @test60_nusw_nuw(
374+
; CHECK-NEXT: [[GEP1_IDX:%.*]] = shl nuw nsw i64 [[I:%.*]], 2
375+
; CHECK-NEXT: [[CMP:%.*]] = icmp samesign ult i64 [[GEP1_IDX]], [[J:%.*]]
376+
; CHECK-NEXT: ret i1 [[CMP]]
377+
;
378+
%gep1 = getelementptr nusw nuw i32, ptr %foo, i64 %i
379+
%gep2 = getelementptr nusw nuw i8, ptr %foo, i64 %j
380+
%cmp = icmp ult ptr %gep1, %gep2
381+
ret i1 %cmp
382+
}
383+
384+
define i1 @test60_nusw_nuw_mix(ptr %foo, i64 %i, i64 %j) {
385+
; CHECK-LABEL: @test60_nusw_nuw_mix(
386+
; CHECK-NEXT: [[GEP1:%.*]] = getelementptr nuw i32, ptr [[FOO:%.*]], i64 [[I:%.*]]
387+
; CHECK-NEXT: [[GEP2:%.*]] = getelementptr nusw i8, ptr [[FOO]], i64 [[J:%.*]]
388+
; CHECK-NEXT: [[CMP:%.*]] = icmp ult ptr [[GEP1]], [[GEP2]]
389+
; CHECK-NEXT: ret i1 [[CMP]]
390+
;
391+
%gep1 = getelementptr nuw i32, ptr %foo, i64 %i
392+
%gep2 = getelementptr nusw i8, ptr %foo, i64 %j
393+
%cmp = icmp ult ptr %gep1, %gep2
394+
ret i1 %cmp
395+
}
396+
322397
define i1 @test_gep_ult_no_inbounds(ptr %foo, i64 %i, i64 %j) {
323398
; CHECK-LABEL: @test_gep_ult_no_inbounds(
324399
; CHECK-NEXT: [[GEP1:%.*]] = getelementptr i32, ptr [[FOO:%.*]], i64 [[I:%.*]]

0 commit comments

Comments
 (0)