From 85c1c964dc5b73085f2b2dce1cfc171fa9b765e2 Mon Sep 17 00:00:00 2001 From: Chris Lattner Date: Fri, 1 Jan 2010 22:42:29 +0000 Subject: [PATCH] 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 --- .../Scalar/InstructionCombining.cpp | 56 +++++++++++++++---- test/Transforms/InstCombine/sub.ll | 13 +++++ 2 files changed, 59 insertions(+), 10 deletions(-) diff --git a/lib/Transforms/Scalar/InstructionCombining.cpp b/lib/Transforms/Scalar/InstructionCombining.cpp index 6c5a16c3615..527d28e2097 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; + GetElementPtrInst *GEP = 0; + ConstantExpr *CstGEP = 0; - if ((GEP = dyn_cast(LHS)) && - GEP->getOperand(0) == RHS) - Swapped = false; - else if ((GEP = dyn_cast(RHS)) && - GEP->getOperand(0) == LHS) - Swapped = true; - else + // 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(LHS)) { + // (gep X, ...) - X + if (LHSGEP->getOperand(0) == RHS) { + GEP = LHSGEP; + Swapped = false; + } else if (ConstantExpr *CE = dyn_cast(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(RHS)) { + // X - (gep X, ...) + if (RHSGEP->getOperand(0) == LHS) { + GEP = RHSGEP; + Swapped = true; + } else if (ConstantExpr *CE = dyn_cast(LHS)) { + // (ce_gep X, ...) - (gep X, ...) + if (CE->getOpcode() == Instruction::GetElementPtr && + RHSGEP->getOperand(0) == CE->getOperand(0)) { + CstGEP = CE; + GEP = RHSGEP; + Swapped = true; + } + } + } + + if (GEP == 0) return 0; - // TODO: Could also optimize &A[i] - &A[j] -> "i-j". - // 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 85ee64ec43f..f8f7c447fa8 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 +} + +