aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Lattner <sabre@nondot.org>2010-01-01 22:42:29 +0000
committerChris Lattner <sabre@nondot.org>2010-01-01 22:42:29 +0000
commit85c1c964dc5b73085f2b2dce1cfc171fa9b765e2 (patch)
treec4335ee741506654a5e7d0dcc8148f8d7402930f
parentf2ebc682d1ee008782d44261f28e92bf982790c2 (diff)
generalize the pointer difference optimization to handle
a constantexpr gep on the 'base' side of the expression. This completes comment #4 in PR3351, which comes from 483.xalancbmk. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@92402 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--lib/Transforms/Scalar/InstructionCombining.cpp58
-rw-r--r--test/Transforms/InstCombine/sub.ll13
2 files changed, 60 insertions, 11 deletions
diff --git a/lib/Transforms/Scalar/InstructionCombining.cpp b/lib/Transforms/Scalar/InstructionCombining.cpp
index 6c5a16c361..527d28e209 100644
--- a/lib/Transforms/Scalar/InstructionCombining.cpp
+++ b/lib/Transforms/Scalar/InstructionCombining.cpp
@@ -2770,21 +2770,57 @@ Value *InstCombiner::OptimizePointerDifference(Value *LHS, Value *RHS,
// If LHS is a gep based on RHS or RHS is a gep based on LHS, we can optimize
// this.
bool Swapped;
- GetElementPtrInst *GEP;
-
- if ((GEP = dyn_cast<GetElementPtrInst>(LHS)) &&
- GEP->getOperand(0) == RHS)
- Swapped = false;
- else if ((GEP = dyn_cast<GetElementPtrInst>(RHS)) &&
- GEP->getOperand(0) == LHS)
- Swapped = true;
- else
- return 0;
+ GetElementPtrInst *GEP = 0;
+ ConstantExpr *CstGEP = 0;
+
+ // TODO: Could also optimize &A[i] - &A[j] -> "i-j", and "&A.foo[i] - &A.foo".
+ // For now we require one side to be the base pointer "A" or a constant
+ // expression derived from it.
+ if (GetElementPtrInst *LHSGEP = dyn_cast<GetElementPtrInst>(LHS)) {
+ // (gep X, ...) - X
+ if (LHSGEP->getOperand(0) == RHS) {
+ GEP = LHSGEP;
+ Swapped = false;
+ } else if (ConstantExpr *CE = dyn_cast<ConstantExpr>(RHS)) {
+ // (gep X, ...) - (ce_gep X, ...)
+ if (CE->getOpcode() == Instruction::GetElementPtr &&
+ LHSGEP->getOperand(0) == CE->getOperand(0)) {
+ CstGEP = CE;
+ GEP = LHSGEP;
+ Swapped = false;
+ }
+ }
+ }
+
+ if (GetElementPtrInst *RHSGEP = dyn_cast<GetElementPtrInst>(RHS)) {
+ // X - (gep X, ...)
+ if (RHSGEP->getOperand(0) == LHS) {
+ GEP = RHSGEP;
+ Swapped = true;
+ } else if (ConstantExpr *CE = dyn_cast<ConstantExpr>(LHS)) {
+ // (ce_gep X, ...) - (gep X, ...)
+ if (CE->getOpcode() == Instruction::GetElementPtr &&
+ RHSGEP->getOperand(0) == CE->getOperand(0)) {
+ CstGEP = CE;
+ GEP = RHSGEP;
+ Swapped = true;
+ }
+ }
+ }
- // TODO: Could also optimize &A[i] - &A[j] -> "i-j".
+ if (GEP == 0)
+ return 0;
// Emit the offset of the GEP and an intptr_t.
Value *Result = EmitGEPOffset(GEP, *this);
+
+ // If we had a constant expression GEP on the other side offsetting the
+ // pointer, subtract it from the offset we have.
+ if (CstGEP) {
+ Value *CstOffset = EmitGEPOffset(CstGEP, *this);
+ Result = Builder->CreateSub(Result, CstOffset);
+ }
+
// If we have p - gep(p, ...) then we have to negate the result.
if (Swapped)
diff --git a/test/Transforms/InstCombine/sub.ll b/test/Transforms/InstCombine/sub.ll
index 85ee64ec43..f8f7c447fa 100644
--- a/test/Transforms/InstCombine/sub.ll
+++ b/test/Transforms/InstCombine/sub.ll
@@ -260,3 +260,16 @@ define i64 @test24b(i8* %P, i64 %A){
; CHECK-NEXT: ret i64
}
+
+define i64 @test25(i8* %P, i64 %A){
+ %B = getelementptr inbounds [42 x i16]* @Arr, i64 0, i64 %A
+ %C = ptrtoint i16* %B to i64
+ %G = sub i64 %C, ptrtoint (i16* getelementptr ([42 x i16]* @Arr, i64 1, i64 0) to i64)
+ ret i64 %G
+; CHECK: @test25
+; CHECK-NEXT: shl i64 %A, 1
+; CHECK-NEXT: add i64 {{.*}}, -84
+; CHECK-NEXT: ret i64
+}
+
+