Skip to content

Commit

Permalink
Use the basic cost if a GEP is not used as addressing mode
Browse files Browse the repository at this point in the history
Summary:
Currently, getGEPCost() returns TCC_FREE whenever a GEP is a legal addressing mode in the target.
However, since it doesn't check its actual users, it will return FREE even in cases
where the GEP cannot be folded away as a part of actual addressing mode.
For example, if an user of the GEP is a call instruction taking the GEP as a parameter,
then the GEP may not be folded in isel.

Reviewers: hfinkel, efriedma, mcrosier, jingyue, haicheng

Reviewed By: hfinkel

Subscribers: javed.absar, llvm-commits

Differential Revision: https://reviews.llvm.org/D38085

llvm-svn: 314517
  • Loading branch information
Jun Bum Lim committed Sep 29, 2017
1 parent c9e363a commit 0e16a59
Show file tree
Hide file tree
Showing 9 changed files with 107 additions and 11 deletions.
19 changes: 16 additions & 3 deletions llvm/include/llvm/Analysis/TargetTransformInfo.h
Expand Up @@ -193,6 +193,13 @@ class TargetTransformInfo {
int getGEPCost(Type *PointeeType, const Value *Ptr,
ArrayRef<const Value *> Operands) const;

/// \brief Estimate the cost of a GEP operation when lowered.
///
/// This user-based overload adds the ability to check if the GEP can be
/// folded into its users.
int getGEPCost(const GEPOperator *GEP,
ArrayRef<const Value *> Operands) const;

/// \brief Estimate the cost of a EXT operation when lowered.
///
/// The contract for this function is the same as \c getOperationCost except
Expand Down Expand Up @@ -251,9 +258,9 @@ class TargetTransformInfo {
/// \brief Estimate the cost of a given IR user when lowered.
///
/// This can estimate the cost of either a ConstantExpr or Instruction when
/// lowered. It has two primary advantages over the \c getOperationCost and
/// \c getGEPCost above, and one significant disadvantage: it can only be
/// used when the IR construct has already been formed.
/// lowered. It has two primary advantages over the \c getOperationCost above,
/// and one significant disadvantage: it can only be used when the IR
/// construct has already been formed.
///
/// The advantages are that it can inspect the SSA use graph to reason more
/// accurately about the cost. For example, all-constant-GEPs can often be
Expand Down Expand Up @@ -932,6 +939,8 @@ class TargetTransformInfo::Concept {
virtual int getOperationCost(unsigned Opcode, Type *Ty, Type *OpTy) = 0;
virtual int getGEPCost(Type *PointeeType, const Value *Ptr,
ArrayRef<const Value *> Operands) = 0;
virtual int getGEPCost(const GEPOperator *GEP,
ArrayRef<const Value *> Operands) = 0;
virtual int getExtCost(const Instruction *I, const Value *Src) = 0;
virtual int getCallCost(FunctionType *FTy, int NumArgs) = 0;
virtual int getCallCost(const Function *F, int NumArgs) = 0;
Expand Down Expand Up @@ -1113,6 +1122,10 @@ class TargetTransformInfo::Model final : public TargetTransformInfo::Concept {
ArrayRef<const Value *> Operands) override {
return Impl.getGEPCost(PointeeType, Ptr, Operands);
}
int getGEPCost(const GEPOperator *GEP,
ArrayRef<const Value *> Operands) override {
return Impl.getGEPCost(GEP, Operands);
}
int getExtCost(const Instruction *I, const Value *Src) override {
return Impl.getExtCost(I, Src);
}
Expand Down
36 changes: 31 additions & 5 deletions llvm/include/llvm/Analysis/TargetTransformInfoImpl.h
Expand Up @@ -726,6 +726,35 @@ class TargetTransformInfoImplCRTPBase : public TargetTransformInfoImplBase {
return TTI::TCC_Basic;
}

int getGEPCost(const GEPOperator *GEP, ArrayRef<const Value *> Operands) {
Type *PointeeType = GEP->getSourceElementType();
const Value *Ptr = GEP->getPointerOperand();

if (getGEPCost(PointeeType, Ptr, Operands) == TTI::TCC_Free) {
// Should check if the GEP is actually used in load / store instructions.
// For simplicity, we check only direct users of the GEP.
//
// FIXME: GEPs could also be folded away as a part of addressing mode in
// load/store instructions together with other instructions (e.g., other
// GEPs). Handling all such cases must be expensive to be performed
// in this function, so we stay conservative for now.
for (const User *U : GEP->users()) {
const Operator *UOP = cast<Operator>(U);
const Value *PointerOperand = nullptr;
if (auto *LI = dyn_cast<LoadInst>(UOP))
PointerOperand = LI->getPointerOperand();
else if (auto *SI = dyn_cast<StoreInst>(UOP))
PointerOperand = SI->getPointerOperand();

if ((!PointerOperand || PointerOperand != GEP) &&
!GEP->hasAllZeroIndices())
return TTI::TCC_Basic;
}
return TTI::TCC_Free;
}
return TTI::TCC_Basic;
}

using BaseT::getIntrinsicCost;

unsigned getIntrinsicCost(Intrinsic::ID IID, Type *RetTy,
Expand All @@ -749,11 +778,8 @@ class TargetTransformInfoImplCRTPBase : public TargetTransformInfoImplBase {
if (A->isStaticAlloca())
return TTI::TCC_Free;

if (const GEPOperator *GEP = dyn_cast<GEPOperator>(U)) {
return static_cast<T *>(this)->getGEPCost(GEP->getSourceElementType(),
GEP->getPointerOperand(),
Operands.drop_front());
}
if (const GEPOperator *GEP = dyn_cast<GEPOperator>(U))
return static_cast<T *>(this)->getGEPCost(GEP, Operands.drop_front());

if (auto CS = ImmutableCallSite(U)) {
const Function *F = CS.getCalledFunction();
Expand Down
4 changes: 4 additions & 0 deletions llvm/include/llvm/CodeGen/BasicTTIImpl.h
Expand Up @@ -151,6 +151,10 @@ class BasicTTIImplBase : public TargetTransformInfoImplCRTPBase<T> {
return BaseT::getGEPCost(PointeeType, Ptr, Operands);
}

int getGEPCost(const GEPOperator *GEP, ArrayRef<const Value *> Operands) {
return BaseT::getGEPCost(GEP, Operands);
}

int getExtCost(const Instruction *I, const Value *Src) {
if (getTLI()->isExtFree(I))
return TargetTransformInfo::TCC_Free;
Expand Down
2 changes: 2 additions & 0 deletions llvm/include/llvm/IR/Operator.h
Expand Up @@ -456,6 +456,8 @@ class GEPOperator
if (ConstantInt *C = dyn_cast<ConstantInt>(I))
if (C->isZero())
continue;
if (isa<ConstantAggregateZero>(I))
continue;
return false;
}
return true;
Expand Down
5 changes: 5 additions & 0 deletions llvm/lib/Analysis/TargetTransformInfo.cpp
Expand Up @@ -88,6 +88,11 @@ int TargetTransformInfo::getGEPCost(Type *PointeeType, const Value *Ptr,
return TTIImpl->getGEPCost(PointeeType, Ptr, Operands);
}

int TargetTransformInfo::getGEPCost(const GEPOperator *GEP,
ArrayRef<const Value *> Operands) const {
return TTIImpl->getGEPCost(GEP, Operands);
}

int TargetTransformInfo::getExtCost(const Instruction *I,
const Value *Src) const {
return TTIImpl->getExtCost(I, Src);
Expand Down
2 changes: 1 addition & 1 deletion llvm/lib/Transforms/Scalar/NaryReassociate.cpp
Expand Up @@ -264,7 +264,7 @@ static bool isGEPFoldable(GetElementPtrInst *GEP,
SmallVector<const Value*, 4> Indices;
for (auto I = GEP->idx_begin(); I != GEP->idx_end(); ++I)
Indices.push_back(*I);
return TTI->getGEPCost(GEP->getSourceElementType(), GEP->getPointerOperand(),
return TTI->getGEPCost(cast<GEPOperator>(GEP),
Indices) == TargetTransformInfo::TCC_Free;
}

Expand Down
2 changes: 1 addition & 1 deletion llvm/lib/Transforms/Scalar/StraightLineStrengthReduce.cpp
Expand Up @@ -239,7 +239,7 @@ static bool isGEPFoldable(GetElementPtrInst *GEP,
SmallVector<const Value*, 4> Indices;
for (auto I = GEP->idx_begin(); I != GEP->idx_end(); ++I)
Indices.push_back(*I);
return TTI->getGEPCost(GEP->getSourceElementType(), GEP->getPointerOperand(),
return TTI->getGEPCost(cast<GEPOperator>(GEP),
Indices) == TargetTransformInfo::TCC_Free;
}

Expand Down
46 changes: 46 additions & 0 deletions llvm/test/Analysis/CostModel/AArch64/gep.ll
Expand Up @@ -290,3 +290,49 @@ define i64 @test36(i64* %p) {
%v = load i64, i64* %a
ret i64 %v
}

; CHECK-LABEL: test37
; CHECK: cost of 1 for instruction: {{.*}} = getelementptr inbounds i8*, i8**
define i8 @test37(i64 %j, i8** readonly %P) {
entry:
%arrayidx0 = getelementptr inbounds i8*, i8** %P, i64 %j
%l1 = call i8* @func(i8** %arrayidx0)
ret i8 0
}

; CHECK-LABEL: test38
; CHECK: cost of 1 for instruction: {{.*}} = getelementptr inbounds i8*, i8**
define i8 @test38(i8** readonly %P) {
entry:
%arrayidx0 = getelementptr inbounds i8*, i8** %P, i64 10
%l1 = call i8* @func(i8** %arrayidx0)
ret i8 0
}

; CHECK-LABEL:test39
; CHECK: cost of 0 for instruction: {{.*}} = getelementptr inbounds i8*, i8**
define i8 @test39(i8** readonly %P) {
entry:
%arrayidx0 = getelementptr inbounds i8*, i8** %P, i64 0
%l1 = call i8* @func(i8** %arrayidx0)
ret i8 0
}

; CHECK-LABEL:test40
; CHECK: cost of 1 for instruction: {{.*}} = getelementptr inbounds i8*, i8**
define i8** @test40(i8** readonly %P) {
entry:
%arrayidx0 = getelementptr inbounds i8*, i8** %P, i64 10
ret i8** %arrayidx0
}

; CHECK-LABEL:test41
; CHECK: cost of 1 for instruction: {{.*}} = getelementptr inbounds i8, i8*
define i8 @test41(i8* %V, i8** readonly %P) {
entry:
%arrayidx0 = getelementptr inbounds i8, i8* %V, i64 10
store i8* %arrayidx0, i8** %P
ret i8 0
}

declare i8* @func(i8**)
2 changes: 1 addition & 1 deletion llvm/test/Analysis/CostModel/X86/vector_gep.ll
Expand Up @@ -10,7 +10,7 @@ define <4 x i32> @foov(<4 x %struct.S*> %s, i64 %base){
%vector = shufflevector <4 x i64> %temp, <4 x i64> undef, <4 x i32> zeroinitializer
;CHECK: cost of 0 for instruction: {{.*}} getelementptr inbounds %struct.S
%B = getelementptr inbounds %struct.S, <4 x %struct.S*> %s, <4 x i32> zeroinitializer, <4 x i32> zeroinitializer
;CHECK: cost of 0 for instruction: {{.*}} getelementptr inbounds [1000 x i32]
;CHECK: cost of 1 for instruction: {{.*}} getelementptr inbounds [1000 x i32]
%arrayidx = getelementptr inbounds [1000 x i32], <4 x [1000 x i32]*> %B, <4 x i64> zeroinitializer, <4 x i64> %vector
%res = call <4 x i32> @llvm.masked.gather.v4i32.v4p0i32(<4 x i32*> %arrayidx, i32 4, <4 x i1> <i1 true, i1 true, i1 true, i1 true>, <4 x i32> undef)
ret <4 x i32> %res
Expand Down

0 comments on commit 0e16a59

Please sign in to comment.