mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-06-11 21:38:19 +00:00
InstSimplify: Simplify trivial pointer expressions like b + (e - b)
consider: long long *f(long long *b, long long *e) { return b + (e - b); } we would lower this to something like: define i64* @f(i64* %b, i64* %e) { %1 = ptrtoint i64* %e to i64 %2 = ptrtoint i64* %b to i64 %3 = sub i64 %1, %2 %4 = ashr exact i64 %3, 3 %5 = getelementptr inbounds i64* %b, i64 %4 ret i64* %5 } This should fold away to just 'e'. N.B. This adds m_SpecificInt as a convenient way to match against a particular 64-bit integer when using LLVM's match interface. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@216439 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
@ -362,6 +362,29 @@ struct bind_const_intval_ty {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Match a specified integer value or vector of all elements of that value.
|
||||||
|
struct specific_intval {
|
||||||
|
uint64_t Val;
|
||||||
|
specific_intval(uint64_t V) : Val(V) {}
|
||||||
|
|
||||||
|
template<typename ITy>
|
||||||
|
bool match(ITy *V) {
|
||||||
|
ConstantInt *CI = dyn_cast<ConstantInt>(V);
|
||||||
|
if (!CI && V->getType()->isVectorTy())
|
||||||
|
if (const auto *C = dyn_cast<Constant>(V))
|
||||||
|
CI = dyn_cast_or_null<ConstantInt>(C->getSplatValue());
|
||||||
|
|
||||||
|
if (CI && CI->getBitWidth() <= 64)
|
||||||
|
return CI->getZExtValue() == Val;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Match a specific integer value or vector with all elements equal to the
|
||||||
|
/// value.
|
||||||
|
inline specific_intval m_SpecificInt(uint64_t V) { return specific_intval(V); }
|
||||||
|
|
||||||
/// m_ConstantInt - Match a ConstantInt and bind to its value. This does not
|
/// m_ConstantInt - Match a ConstantInt and bind to its value. This does not
|
||||||
/// match ConstantInts wider than 64-bits.
|
/// match ConstantInts wider than 64-bits.
|
||||||
inline bind_const_intval_ty m_ConstantInt(uint64_t &V) { return V; }
|
inline bind_const_intval_ty m_ConstantInt(uint64_t &V) { return V; }
|
||||||
|
@ -2783,6 +2783,7 @@ Value *llvm::SimplifySelectInst(Value *Cond, Value *TrueVal, Value *FalseVal,
|
|||||||
static Value *SimplifyGEPInst(ArrayRef<Value *> Ops, const Query &Q, unsigned) {
|
static Value *SimplifyGEPInst(ArrayRef<Value *> Ops, const Query &Q, unsigned) {
|
||||||
// The type of the GEP pointer operand.
|
// The type of the GEP pointer operand.
|
||||||
PointerType *PtrTy = cast<PointerType>(Ops[0]->getType()->getScalarType());
|
PointerType *PtrTy = cast<PointerType>(Ops[0]->getType()->getScalarType());
|
||||||
|
unsigned AS = PtrTy->getAddressSpace();
|
||||||
|
|
||||||
// getelementptr P -> P.
|
// getelementptr P -> P.
|
||||||
if (Ops.size() == 1)
|
if (Ops.size() == 1)
|
||||||
@ -2791,7 +2792,7 @@ static Value *SimplifyGEPInst(ArrayRef<Value *> Ops, const Query &Q, unsigned) {
|
|||||||
if (isa<UndefValue>(Ops[0])) {
|
if (isa<UndefValue>(Ops[0])) {
|
||||||
// Compute the (pointer) type returned by the GEP instruction.
|
// Compute the (pointer) type returned by the GEP instruction.
|
||||||
Type *LastType = GetElementPtrInst::getIndexedType(PtrTy, Ops.slice(1));
|
Type *LastType = GetElementPtrInst::getIndexedType(PtrTy, Ops.slice(1));
|
||||||
Type *GEPTy = PointerType::get(LastType, PtrTy->getAddressSpace());
|
Type *GEPTy = PointerType::get(LastType, AS);
|
||||||
if (VectorType *VT = dyn_cast<VectorType>(Ops[0]->getType()))
|
if (VectorType *VT = dyn_cast<VectorType>(Ops[0]->getType()))
|
||||||
GEPTy = VectorType::get(GEPTy, VT->getNumElements());
|
GEPTy = VectorType::get(GEPTy, VT->getNumElements());
|
||||||
return UndefValue::get(GEPTy);
|
return UndefValue::get(GEPTy);
|
||||||
@ -2801,11 +2802,41 @@ static Value *SimplifyGEPInst(ArrayRef<Value *> Ops, const Query &Q, unsigned) {
|
|||||||
// getelementptr P, 0 -> P.
|
// getelementptr P, 0 -> P.
|
||||||
if (match(Ops[1], m_Zero()))
|
if (match(Ops[1], m_Zero()))
|
||||||
return Ops[0];
|
return Ops[0];
|
||||||
// getelementptr P, N -> P if P points to a type of zero size.
|
|
||||||
if (Q.DL) {
|
Type *Ty = PtrTy->getElementType();
|
||||||
Type *Ty = PtrTy->getElementType();
|
if (Q.DL && Ty->isSized()) {
|
||||||
if (Ty->isSized() && Q.DL->getTypeAllocSize(Ty) == 0)
|
Value *P;
|
||||||
|
uint64_t C;
|
||||||
|
uint64_t TyAllocSize = Q.DL->getTypeAllocSize(Ty);
|
||||||
|
// getelementptr P, N -> P if P points to a type of zero size.
|
||||||
|
if (TyAllocSize == 0)
|
||||||
return Ops[0];
|
return Ops[0];
|
||||||
|
|
||||||
|
// The following transforms are only safe if the ptrtoint cast
|
||||||
|
// doesn't truncate the pointers.
|
||||||
|
if (Ops[1]->getType()->getScalarSizeInBits() ==
|
||||||
|
Q.DL->getPointerSizeInBits(AS)) {
|
||||||
|
// getelementptr P, (sub Q, P) -> Q if P points to a type of size 1.
|
||||||
|
if (TyAllocSize == 1 &&
|
||||||
|
match(Ops[1], m_Sub(m_PtrToInt(m_Value(P)),
|
||||||
|
m_PtrToInt(m_Specific(Ops[0])))))
|
||||||
|
return P;
|
||||||
|
|
||||||
|
// getelementptr P, (ashr (sub Q, P), C) -> Q
|
||||||
|
// if P points to a type of size 1 << C.
|
||||||
|
if (match(Ops[1], m_AShr(m_Sub(m_PtrToInt(m_Value(P)),
|
||||||
|
m_PtrToInt(m_Specific(Ops[0]))),
|
||||||
|
m_ConstantInt(C))) &&
|
||||||
|
TyAllocSize == 1ULL << C)
|
||||||
|
return P;
|
||||||
|
|
||||||
|
// getelementptr P, (sdiv (sub Q, P), C) -> Q
|
||||||
|
// if P points to a type of size C.
|
||||||
|
if (match(Ops[1], m_SDiv(m_Sub(m_PtrToInt(m_Value(P)),
|
||||||
|
m_PtrToInt(m_Specific(Ops[0]))),
|
||||||
|
m_SpecificInt(TyAllocSize))))
|
||||||
|
return P;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
37
test/Transforms/InstSimplify/gep.ll
Normal file
37
test/Transforms/InstSimplify/gep.ll
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
; RUN: opt -S -instsimplify < %s | FileCheck %s
|
||||||
|
|
||||||
|
target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
|
||||||
|
|
||||||
|
%struct.A = type { [7 x i8] }
|
||||||
|
|
||||||
|
define %struct.A* @test1(%struct.A* %b, %struct.A* %e) {
|
||||||
|
%e_ptr = ptrtoint %struct.A* %e to i64
|
||||||
|
%b_ptr = ptrtoint %struct.A* %b to i64
|
||||||
|
%sub = sub i64 %e_ptr, %b_ptr
|
||||||
|
%sdiv = sdiv exact i64 %sub, 7
|
||||||
|
%gep = getelementptr inbounds %struct.A* %b, i64 %sdiv
|
||||||
|
ret %struct.A* %gep
|
||||||
|
; CHECK-LABEL: @test1
|
||||||
|
; CHECK-NEXT: ret %struct.A* %e
|
||||||
|
}
|
||||||
|
|
||||||
|
define i8* @test2(i8* %b, i8* %e) {
|
||||||
|
%e_ptr = ptrtoint i8* %e to i64
|
||||||
|
%b_ptr = ptrtoint i8* %b to i64
|
||||||
|
%sub = sub i64 %e_ptr, %b_ptr
|
||||||
|
%gep = getelementptr inbounds i8* %b, i64 %sub
|
||||||
|
ret i8* %gep
|
||||||
|
; CHECK-LABEL: @test2
|
||||||
|
; CHECK-NEXT: ret i8* %e
|
||||||
|
}
|
||||||
|
|
||||||
|
define i64* @test3(i64* %b, i64* %e) {
|
||||||
|
%e_ptr = ptrtoint i64* %e to i64
|
||||||
|
%b_ptr = ptrtoint i64* %b to i64
|
||||||
|
%sub = sub i64 %e_ptr, %b_ptr
|
||||||
|
%ashr = ashr exact i64 %sub, 3
|
||||||
|
%gep = getelementptr inbounds i64* %b, i64 %ashr
|
||||||
|
ret i64* %gep
|
||||||
|
; CHECK-LABEL: @test3
|
||||||
|
; CHECK-NEXT: ret i64* %e
|
||||||
|
}
|
Reference in New Issue
Block a user