mirror of
https://github.com/RPCS3/llvm.git
synced 2025-02-17 01:09:01 +00:00
InstCombine: Make OptimizePointerDifference more aggressive.
- Ignore pointer casts. - Also expand GEPs that aren't constantexprs when they have one use or only constant indices. - We now compile "&foo[i] - &foo[j]" into "i - j". git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@150961 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
6259dcdc57
commit
d2348639e6
@ -479,57 +479,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
|
// If LHS is a gep based on RHS or RHS is a gep based on LHS, we can optimize
|
||||||
// this.
|
// this.
|
||||||
bool Swapped = false;
|
bool Swapped = false;
|
||||||
GetElementPtrInst *GEP = 0;
|
GEPOperator *GEP1 = 0, *GEP2 = 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
|
// For now we require one side to be the base pointer "A" or a constant
|
||||||
// expression derived from it.
|
// GEP derived from it.
|
||||||
if (GetElementPtrInst *LHSGEP = dyn_cast<GetElementPtrInst>(LHS)) {
|
if (GEPOperator *LHSGEP = dyn_cast<GEPOperator>(LHS)) {
|
||||||
// (gep X, ...) - X
|
// (gep X, ...) - X
|
||||||
if (LHSGEP->getOperand(0) == RHS) {
|
if (LHSGEP->getOperand(0) == RHS) {
|
||||||
GEP = LHSGEP;
|
GEP1 = LHSGEP;
|
||||||
Swapped = false;
|
Swapped = false;
|
||||||
} else if (ConstantExpr *CE = dyn_cast<ConstantExpr>(RHS)) {
|
} else if (GEPOperator *RHSGEP = dyn_cast<GEPOperator>(RHS)) {
|
||||||
// (gep X, ...) - (ce_gep X, ...)
|
// (gep X, ...) - (gep X, ...)
|
||||||
if (CE->getOpcode() == Instruction::GetElementPtr &&
|
if (LHSGEP->getOperand(0)->stripPointerCasts() ==
|
||||||
LHSGEP->getOperand(0) == CE->getOperand(0)) {
|
RHSGEP->getOperand(0)->stripPointerCasts()) {
|
||||||
CstGEP = CE;
|
GEP2 = RHSGEP;
|
||||||
GEP = LHSGEP;
|
GEP1 = LHSGEP;
|
||||||
Swapped = false;
|
Swapped = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (GetElementPtrInst *RHSGEP = dyn_cast<GetElementPtrInst>(RHS)) {
|
if (GEPOperator *RHSGEP = dyn_cast<GEPOperator>(RHS)) {
|
||||||
// X - (gep X, ...)
|
// X - (gep X, ...)
|
||||||
if (RHSGEP->getOperand(0) == LHS) {
|
if (RHSGEP->getOperand(0) == LHS) {
|
||||||
GEP = RHSGEP;
|
GEP1 = RHSGEP;
|
||||||
Swapped = true;
|
Swapped = true;
|
||||||
} else if (ConstantExpr *CE = dyn_cast<ConstantExpr>(LHS)) {
|
} else if (GEPOperator *LHSGEP = dyn_cast<GEPOperator>(LHS)) {
|
||||||
// (ce_gep X, ...) - (gep X, ...)
|
// (gep X, ...) - (gep X, ...)
|
||||||
if (CE->getOpcode() == Instruction::GetElementPtr &&
|
if (RHSGEP->getOperand(0)->stripPointerCasts() ==
|
||||||
RHSGEP->getOperand(0) == CE->getOperand(0)) {
|
LHSGEP->getOperand(0)->stripPointerCasts()) {
|
||||||
CstGEP = CE;
|
GEP2 = LHSGEP;
|
||||||
GEP = RHSGEP;
|
GEP1 = RHSGEP;
|
||||||
Swapped = true;
|
Swapped = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (GEP == 0)
|
// Avoid duplicating the arithmetic if GEP2 has non-constant indices and
|
||||||
|
// multiple users.
|
||||||
|
if (GEP1 == 0 ||
|
||||||
|
(GEP2 != 0 && !GEP2->hasAllConstantIndices() && !GEP2->hasOneUse()))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
// Emit the offset of the GEP and an intptr_t.
|
// Emit the offset of the GEP and an intptr_t.
|
||||||
Value *Result = EmitGEPOffset(GEP);
|
Value *Result = EmitGEPOffset(GEP1);
|
||||||
|
|
||||||
// If we had a constant expression GEP on the other side offsetting the
|
// If we had a constant expression GEP on the other side offsetting the
|
||||||
// pointer, subtract it from the offset we have.
|
// pointer, subtract it from the offset we have.
|
||||||
if (CstGEP) {
|
if (GEP2) {
|
||||||
Value *CstOffset = EmitGEPOffset(CstGEP);
|
Value *Offset = EmitGEPOffset(GEP2);
|
||||||
Result = Builder->CreateSub(Result, CstOffset);
|
Result = Builder->CreateSub(Result, Offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// If we have p - gep(p, ...) then we have to negate the result.
|
// If we have p - gep(p, ...) then we have to negate the result.
|
||||||
if (Swapped)
|
if (Swapped)
|
||||||
|
@ -301,3 +301,29 @@ define i32 @test28(i32 %x, i32 %y, i32 %z) {
|
|||||||
; CHECK-NEXT: add i32
|
; CHECK-NEXT: add i32
|
||||||
; CHECK-NEXT: ret i32
|
; CHECK-NEXT: ret i32
|
||||||
}
|
}
|
||||||
|
|
||||||
|
define i64 @test29(i8* %foo, i64 %i, i64 %j) {
|
||||||
|
%gep1 = getelementptr inbounds i8* %foo, i64 %i
|
||||||
|
%gep2 = getelementptr inbounds i8* %foo, i64 %j
|
||||||
|
%cast1 = ptrtoint i8* %gep1 to i64
|
||||||
|
%cast2 = ptrtoint i8* %gep2 to i64
|
||||||
|
%sub = sub i64 %cast1, %cast2
|
||||||
|
ret i64 %sub
|
||||||
|
; CHECK: @test29
|
||||||
|
; CHECK-NEXT: sub i64 %i, %j
|
||||||
|
; CHECK-NEXT: ret i64
|
||||||
|
}
|
||||||
|
|
||||||
|
define i64 @test30(i8* %foo, i64 %i, i64 %j) {
|
||||||
|
%bit = bitcast i8* %foo to i32*
|
||||||
|
%gep1 = getelementptr inbounds i32* %bit, i64 %i
|
||||||
|
%gep2 = getelementptr inbounds i8* %foo, i64 %j
|
||||||
|
%cast1 = ptrtoint i32* %gep1 to i64
|
||||||
|
%cast2 = ptrtoint i8* %gep2 to i64
|
||||||
|
%sub = sub i64 %cast1, %cast2
|
||||||
|
ret i64 %sub
|
||||||
|
; CHECK: @test30
|
||||||
|
; CHECK-NEXT: %gep1.idx = shl nuw i64 %i, 2
|
||||||
|
; CHECK-NEXT: sub i64 %gep1.idx, %j
|
||||||
|
; CHECK-NEXT: ret i64
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user