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
This commit is contained in:
Chris Lattner 2010-01-01 22:42:29 +00:00
parent f2ebc682d1
commit 85c1c964dc
2 changed files with 59 additions and 10 deletions

View File

@ -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<GetElementPtrInst>(LHS)) &&
GEP->getOperand(0) == RHS)
Swapped = false;
else if ((GEP = dyn_cast<GetElementPtrInst>(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<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;
}
}
}
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)

View File

@ -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
}