Skip to content

Commit cbe1760

Browse files
authored
[InstCombine] Allow multi-use OptimizePointerDifference() with two GEPs (#90017)
Currently, the OptimizePointerDifference fold does not trigger when working on the sub of two geps where one of the geps has multiple uses, to avoid duplicating the offset arithmetic too much. However, there are cases where performing it would still be clearly profitable, e.g. test_sub_ptradd_multiuse. This patch drops the one-use restriction using the same strategy we use in GEP comparison folds: If there are multiple uses, we rewrite the GEP to use the expanded offset arithmetic instead (effectively canonicalizing it into ptradd representation). Fixes #88231.
1 parent e21d89e commit cbe1760

File tree

2 files changed

+20
-40
lines changed

2 files changed

+20
-40
lines changed

llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp

Lines changed: 6 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2001,29 +2001,13 @@ Value *InstCombinerImpl::OptimizePointerDifference(Value *LHS, Value *RHS,
20012001
if (!GEP1)
20022002
return nullptr;
20032003

2004-
if (GEP2) {
2005-
// (gep X, ...) - (gep X, ...)
2006-
//
2007-
// Avoid duplicating the arithmetic if there are more than one non-constant
2008-
// indices between the two GEPs and either GEP has a non-constant index and
2009-
// multiple users. If zero non-constant index, the result is a constant and
2010-
// there is no duplication. If one non-constant index, the result is an add
2011-
// or sub with a constant, which is no larger than the original code, and
2012-
// there's no duplicated arithmetic, even if either GEP has multiple
2013-
// users. If more than one non-constant indices combined, as long as the GEP
2014-
// with at least one non-constant index doesn't have multiple users, there
2015-
// is no duplication.
2016-
unsigned NumNonConstantIndices1 = GEP1->countNonConstantIndices();
2017-
unsigned NumNonConstantIndices2 = GEP2->countNonConstantIndices();
2018-
if (NumNonConstantIndices1 + NumNonConstantIndices2 > 1 &&
2019-
((NumNonConstantIndices1 > 0 && !GEP1->hasOneUse()) ||
2020-
(NumNonConstantIndices2 > 0 && !GEP2->hasOneUse()))) {
2021-
return nullptr;
2022-
}
2023-
}
2004+
// To avoid duplicating the offset arithmetic, rewrite the GEP to use the
2005+
// computed offset.
2006+
// TODO: We should probably do this even if there is only one GEP.
2007+
bool RewriteGEPs = GEP2 != nullptr;
20242008

20252009
// Emit the offset of the GEP and an intptr_t.
2026-
Value *Result = EmitGEPOffset(GEP1);
2010+
Value *Result = EmitGEPOffset(GEP1, RewriteGEPs);
20272011

20282012
// If this is a single inbounds GEP and the original sub was nuw,
20292013
// then the final multiplication is also nuw.
@@ -2035,7 +2019,7 @@ Value *InstCombinerImpl::OptimizePointerDifference(Value *LHS, Value *RHS,
20352019
// If we have a 2nd GEP of the same base pointer, subtract the offsets.
20362020
// If both GEPs are inbounds, then the subtract does not have signed overflow.
20372021
if (GEP2) {
2038-
Value *Offset = EmitGEPOffset(GEP2);
2022+
Value *Offset = EmitGEPOffset(GEP2, RewriteGEPs);
20392023
Result = Builder.CreateSub(Result, Offset, "gepdiff", /* NUW */ false,
20402024
GEP1->isInBounds() && GEP2->isInBounds());
20412025
}

llvm/test/Transforms/InstCombine/sub.ll

Lines changed: 14 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1123,7 +1123,8 @@ define i64 @test58(ptr %foo, i64 %i, i64 %j) {
11231123

11241124
define i64 @test59(ptr %foo, i64 %i) {
11251125
; CHECK-LABEL: @test59(
1126-
; CHECK-NEXT: [[GEP1:%.*]] = getelementptr inbounds [100 x [100 x i8]], ptr [[FOO:%.*]], i64 0, i64 42, i64 [[I:%.*]]
1126+
; CHECK-NEXT: [[TMP1:%.*]] = getelementptr i8, ptr [[FOO:%.*]], i64 [[I:%.*]]
1127+
; CHECK-NEXT: [[GEP1:%.*]] = getelementptr i8, ptr [[TMP1]], i64 4200
11271128
; CHECK-NEXT: [[GEP2:%.*]] = getelementptr inbounds i8, ptr [[FOO]], i64 4200
11281129
; CHECK-NEXT: store ptr [[GEP1]], ptr @dummy_global1, align 8
11291130
; CHECK-NEXT: store ptr [[GEP2]], ptr @dummy_global2, align 8
@@ -1142,13 +1143,12 @@ define i64 @test59(ptr %foo, i64 %i) {
11421143

11431144
define i64 @test60(ptr %foo, i64 %i, i64 %j) {
11441145
; CHECK-LABEL: @test60(
1145-
; CHECK-NEXT: [[GEP1:%.*]] = getelementptr inbounds [100 x [100 x i8]], ptr [[FOO:%.*]], i64 0, i64 [[J:%.*]], i64 [[I:%.*]]
1146-
; CHECK-NEXT: [[GEP2:%.*]] = getelementptr inbounds i8, ptr [[FOO]], i64 4200
1147-
; CHECK-NEXT: [[CAST1:%.*]] = ptrtoint ptr [[GEP1]] to i64
1148-
; CHECK-NEXT: [[CAST2:%.*]] = ptrtoint ptr [[GEP2]] to i64
1149-
; CHECK-NEXT: [[SUB:%.*]] = sub i64 [[CAST1]], [[CAST2]]
1146+
; CHECK-NEXT: [[GEP1_IDX:%.*]] = mul nsw i64 [[J:%.*]], 100
1147+
; CHECK-NEXT: [[GEP1_OFFS:%.*]] = add nsw i64 [[GEP1_IDX]], [[I:%.*]]
1148+
; CHECK-NEXT: [[GEP1:%.*]] = getelementptr inbounds i8, ptr [[FOO:%.*]], i64 [[GEP1_OFFS]]
1149+
; CHECK-NEXT: [[GEPDIFF:%.*]] = add nsw i64 [[GEP1_OFFS]], -4200
11501150
; CHECK-NEXT: store ptr [[GEP1]], ptr @dummy_global1, align 8
1151-
; CHECK-NEXT: ret i64 [[SUB]]
1151+
; CHECK-NEXT: ret i64 [[GEPDIFF]]
11521152
;
11531153
; gep1 has a non-constant index and more than one uses. Shouldn't duplicate the arithmetic.
11541154
%gep1 = getelementptr inbounds [100 x [100 x i8]], ptr %foo, i64 0, i64 %j, i64 %i
@@ -1162,13 +1162,12 @@ define i64 @test60(ptr %foo, i64 %i, i64 %j) {
11621162

11631163
define i64 @test61(ptr %foo, i64 %i, i64 %j) {
11641164
; CHECK-LABEL: @test61(
1165-
; CHECK-NEXT: [[GEP1:%.*]] = getelementptr inbounds i8, ptr [[FOO:%.*]], i64 4200
1166-
; CHECK-NEXT: [[GEP2:%.*]] = getelementptr inbounds [100 x [100 x i8]], ptr [[FOO]], i64 0, i64 [[J:%.*]], i64 [[I:%.*]]
1167-
; CHECK-NEXT: [[CAST1:%.*]] = ptrtoint ptr [[GEP1]] to i64
1168-
; CHECK-NEXT: [[CAST2:%.*]] = ptrtoint ptr [[GEP2]] to i64
1169-
; CHECK-NEXT: [[SUB:%.*]] = sub i64 [[CAST1]], [[CAST2]]
1165+
; CHECK-NEXT: [[GEP2_IDX:%.*]] = mul nsw i64 [[J:%.*]], 100
1166+
; CHECK-NEXT: [[GEP2_OFFS:%.*]] = add nsw i64 [[GEP2_IDX]], [[I:%.*]]
1167+
; CHECK-NEXT: [[GEP2:%.*]] = getelementptr inbounds i8, ptr [[FOO:%.*]], i64 [[GEP2_OFFS]]
1168+
; CHECK-NEXT: [[GEPDIFF:%.*]] = sub nsw i64 4200, [[GEP2_OFFS]]
11701169
; CHECK-NEXT: store ptr [[GEP2]], ptr @dummy_global2, align 8
1171-
; CHECK-NEXT: ret i64 [[SUB]]
1170+
; CHECK-NEXT: ret i64 [[GEPDIFF]]
11721171
;
11731172
; gep2 has a non-constant index and more than one uses. Shouldn't duplicate the arithmetic.
11741173
%gep1 = getelementptr inbounds [100 x [100 x i8]], ptr %foo, i64 0, i64 42, i64 0
@@ -1186,11 +1185,8 @@ define i64 @test_sub_ptradd_multiuse(ptr %p, i64 %idx1, i64 %idx2) {
11861185
; CHECK-LABEL: @test_sub_ptradd_multiuse(
11871186
; CHECK-NEXT: [[P1:%.*]] = getelementptr inbounds i8, ptr [[P:%.*]], i64 [[IDX1:%.*]]
11881187
; CHECK-NEXT: call void @use.ptr(ptr [[P1]])
1189-
; CHECK-NEXT: [[P2:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 [[IDX2:%.*]]
1190-
; CHECK-NEXT: [[P1_INT:%.*]] = ptrtoint ptr [[P1]] to i64
1191-
; CHECK-NEXT: [[P2_INT:%.*]] = ptrtoint ptr [[P2]] to i64
1192-
; CHECK-NEXT: [[SUB:%.*]] = sub i64 [[P1_INT]], [[P2_INT]]
1193-
; CHECK-NEXT: ret i64 [[SUB]]
1188+
; CHECK-NEXT: [[GEPDIFF:%.*]] = sub nsw i64 [[IDX1]], [[IDX2:%.*]]
1189+
; CHECK-NEXT: ret i64 [[GEPDIFF]]
11941190
;
11951191
%p1 = getelementptr inbounds i8, ptr %p, i64 %idx1
11961192
call void @use.ptr(ptr %p1)

0 commit comments

Comments
 (0)