-
Notifications
You must be signed in to change notification settings - Fork 14.1k
[CVP] Remove Zero-Index GEP #144831
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
[CVP] Remove Zero-Index GEP #144831
Conversation
@llvm/pr-subscribers-llvm-transforms Author: Veera (veera-sivarajan) ChangesFixes: #137168 Proof: https://alive2.llvm.org/ce/z/Xoyiar Replaces all uses of a GEP with its base pointer when all its indices are known to be in the range [0, 1). This is the same transform as 87a0b1b but in CVP. Full diff: https://github.com/llvm/llvm-project/pull/144831.diff 2 Files Affected:
diff --git a/llvm/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp b/llvm/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp
index 4627f537dc16b..11a3a35d1ae7c 100644
--- a/llvm/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp
+++ b/llvm/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp
@@ -47,6 +47,7 @@ using namespace llvm;
#define DEBUG_TYPE "correlated-value-propagation"
+STATISTIC(NumGEPs, "Number of geps propagated");
STATISTIC(NumPhis, "Number of phis propagated");
STATISTIC(NumPhiCommon, "Number of phis deleted via common incoming value");
STATISTIC(NumSelects, "Number of selects propagated");
@@ -1252,6 +1253,23 @@ static bool processTrunc(TruncInst *TI, LazyValueInfo *LVI) {
return Changed;
}
+// remove a GEP if all indices are in range [0, 1)
+static bool processGEP(GetElementPtrInst *GEP, LazyValueInfo *LVI) {
+ for (unsigned i = 1, e = GEP->getNumOperands(); i != e; ++i) {
+ ConstantRange Range = LVI->getConstantRangeAtUse(GEP->getOperandUse(i),
+ /*UndefAllowed=*/false);
+ const APInt *C = Range.getSingleElement();
+ if (!C || !C->isZero())
+ return false;
+ }
+
+ // all indices are zero
+ Value *Ptr = GEP->getPointerOperand();
+ GEP->replaceAllUsesWith(Ptr);
+ ++NumGEPs;
+ return true;
+}
+
static bool runImpl(Function &F, LazyValueInfo *LVI, DominatorTree *DT,
const SimplifyQuery &SQ) {
bool FnChanged = false;
@@ -1318,6 +1336,9 @@ static bool runImpl(Function &F, LazyValueInfo *LVI, DominatorTree *DT,
case Instruction::Trunc:
BBChanged |= processTrunc(cast<TruncInst>(&II), LVI);
break;
+ case Instruction::GetElementPtr:
+ BBChanged |= processGEP(cast<GetElementPtrInst>(&II), LVI);
+ break;
}
}
diff --git a/llvm/test/Transforms/CorrelatedValuePropagation/gep.ll b/llvm/test/Transforms/CorrelatedValuePropagation/gep.ll
new file mode 100644
index 0000000000000..d5c122b3f665e
--- /dev/null
+++ b/llvm/test/Transforms/CorrelatedValuePropagation/gep.ll
@@ -0,0 +1,45 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
+; RUN: opt < %s -passes=correlated-propagation -S | FileCheck %s
+
+define ptr @noop_gep(ptr %ptr, i8 range(i8 0, 1) %index) {
+; CHECK-LABEL: define ptr @noop_gep(
+; CHECK-SAME: ptr [[PTR:%.*]], i8 range(i8 0, 1) [[INDEX:%.*]]) {
+; CHECK-NEXT: [[GEP:%.*]] = getelementptr i1, ptr [[PTR]], i8 [[INDEX]]
+; CHECK-NEXT: ret ptr [[PTR]]
+;
+ %gep = getelementptr i1, ptr %ptr, i8 %index
+ ret ptr %gep
+}
+
+
+define ptr @noop_gep_with_constant(ptr %ptr, i8 range(i8 0, 1) %index) {
+; CHECK-LABEL: define ptr @noop_gep_with_constant(
+; CHECK-SAME: ptr [[PTR:%.*]], i8 range(i8 0, 1) [[INDEX:%.*]]) {
+; CHECK-NEXT: [[GEP:%.*]] = getelementptr [2 x i1], ptr [[PTR]], i8 0, i8 [[INDEX]]
+; CHECK-NEXT: ret ptr [[PTR]]
+;
+ %gep = getelementptr [2 x i1], ptr %ptr, i8 0, i8 %index
+ ret ptr %gep
+}
+
+
+define ptr @noop_gep_nonzero_index_negative(ptr %ptr, i8 range(i8 0, 2) %index) {
+; CHECK-LABEL: define ptr @noop_gep_nonzero_index_negative(
+; CHECK-SAME: ptr [[PTR:%.*]], i8 range(i8 0, 2) [[INDEX:%.*]]) {
+; CHECK-NEXT: [[GEP:%.*]] = getelementptr i1, ptr [[PTR]], i8 [[INDEX]]
+; CHECK-NEXT: ret ptr [[GEP]]
+;
+ %gep = getelementptr i1, ptr %ptr, i8 %index
+ ret ptr %gep
+}
+
+
+define ptr @gep_no_range_negative(ptr %ptr, i8 %index) {
+; CHECK-LABEL: define ptr @gep_no_range_negative(
+; CHECK-SAME: ptr [[PTR:%.*]], i8 [[INDEX:%.*]]) {
+; CHECK-NEXT: [[GEP:%.*]] = getelementptr i1, ptr [[PTR]], i8 [[INDEX]]
+; CHECK-NEXT: ret ptr [[GEP]]
+;
+ %gep = getelementptr i1, ptr %ptr, i8 %index
+ ret ptr %gep
+}
|
✅ With the latest revision this PR passed the C/C++ code formatter. |
a014cef
to
4cdb154
Compare
|
||
// all indices are zero | ||
Value *Ptr = GEP->getPointerOperand(); | ||
GEP->replaceAllUsesWith(Ptr); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It doesn't work for the form getelementptr ty, scalar ptr, vector indices
. You can create a splat when the type of GEP differs from the type of source pointer.
Crash reproducer:
define <2 x ptr> @noop_gep_nonzero_index_vec(ptr %ptr, <2 x i64> range(i64 0, 1) %index) {
%gep = getelementptr i8, ptr %ptr, <2 x i64> %index
ret <2 x ptr> %gep
}
@@ -1252,6 +1253,23 @@ static bool processTrunc(TruncInst *TI, LazyValueInfo *LVI) { | |||
return Changed; | |||
} | |||
|
|||
// remove a GEP if all indices are in range [0, 1) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// remove a GEP if all indices are in range [0, 1) | |
/// Remove a GEP if all indices are in range [0, 1) |
@@ -1252,6 +1253,23 @@ static bool processTrunc(TruncInst *TI, LazyValueInfo *LVI) { | |||
return Changed; | |||
} | |||
|
|||
// remove a GEP if all indices are in range [0, 1) | |||
static bool processGEP(GetElementPtrInst *GEP, LazyValueInfo *LVI) { | |||
for (unsigned i = 1, e = GEP->getNumOperands(); i != e; ++i) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
for (unsigned i = 1, e = GEP->getNumOperands(); i != e; ++i) { | |
for (unsigned I = 1, E = GEP->getNumOperands(); I != E; ++I) { |
// all indices are zero | ||
Value *Ptr = GEP->getPointerOperand(); | ||
GEP->replaceAllUsesWith(Ptr); | ||
++NumGEPs; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
++NumGEPs; | |
GEP->eraseFromParent(); | |
++NumGEPs; |
; CHECK-NEXT: [[GEP:%.*]] = getelementptr i1, ptr [[PTR]], i8 [[INDEX]] | ||
; CHECK-NEXT: ret ptr [[PTR]] | ||
; | ||
%gep = getelementptr i1, ptr %ptr, i8 %index |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
%gep = getelementptr i1, ptr %ptr, i8 %index | |
%gep = getelementptr i8, ptr %ptr, i64 %index |
Use i8 as the pointee type and i64 as the index type.
@@ -0,0 +1,45 @@ | |||
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5 | |||
; RUN: opt < %s -passes=correlated-propagation -S | FileCheck %s | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you add the motivating case from #137168?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is nothing really GEP specific here -- this just uses LVI to determine whether values are constant. However, there is a reason why we don't actually do this very obvious optimization: Unlike SCCP (which does perform this type of optimization), LVI is very, very slow and we need to keep the number of values we query small.
A possible way to fix the motivating issue is to enable use of PredicateInfo in non-IP SCCP. This will also have compile-time overhead, but probably less than this? We'd have to evaluate whether it is worthwhile. Edit: PredicateInfo compile-time: https://llvm-compile-time-tracker.com/compare.php?from=a9a71b6d311892d6add6aab3790b20fe945cca38&to=e237b4a75e0eadb116cec3fa3227f7f2e95ed996&stat=instructions:u |
Fixes: #137168
Proof: https://alive2.llvm.org/ce/z/Xoyiar
Replaces all uses of a GEP with its base pointer when all its indices are known to be in the range [0, 1).
This is the same transform as 87a0b1b but in CVP.