summaryrefslogtreecommitdiff
path: root/include/llvm/Analysis/TargetTransformInfoImpl.h
diff options
context:
space:
mode:
Diffstat (limited to 'include/llvm/Analysis/TargetTransformInfoImpl.h')
-rw-r--r--include/llvm/Analysis/TargetTransformInfoImpl.h104
1 files changed, 91 insertions, 13 deletions
diff --git a/include/llvm/Analysis/TargetTransformInfoImpl.h b/include/llvm/Analysis/TargetTransformInfoImpl.h
index 9bbda718acab4..4c37402278efe 100644
--- a/include/llvm/Analysis/TargetTransformInfoImpl.h
+++ b/include/llvm/Analysis/TargetTransformInfoImpl.h
@@ -152,6 +152,7 @@ public:
case Intrinsic::annotation:
case Intrinsic::assume:
+ case Intrinsic::sideeffect:
case Intrinsic::dbg_declare:
case Intrinsic::dbg_value:
case Intrinsic::invariant_start:
@@ -188,6 +189,8 @@ public:
}
bool isLoweredToCall(const Function *F) {
+ assert(F && "A concrete function must be provided to this routine.");
+
// FIXME: These should almost certainly not be handled here, and instead
// handled with the help of TLI or the target itself. This was largely
// ported from existing analysis heuristics here so that such refactorings
@@ -230,7 +233,7 @@ public:
bool isLegalAddressingMode(Type *Ty, GlobalValue *BaseGV, int64_t BaseOffset,
bool HasBaseReg, int64_t Scale,
- unsigned AddrSpace) {
+ unsigned AddrSpace, Instruction *I = nullptr) {
// Guess that only reg and reg+reg addressing is allowed. This heuristic is
// taken from the implementation of LSR.
return !BaseGV && BaseOffset == 0 && (Scale == 0 || Scale == 1);
@@ -251,6 +254,10 @@ public:
bool isLegalMaskedGather(Type *DataType) { return false; }
+ bool hasDivRemOp(Type *DataType, bool IsSigned) { return false; }
+
+ bool hasVolatileVariant(Instruction *I, unsigned AddrSpace) { return false; }
+
bool prefersVectorizedAddressing() { return true; }
int getScalingFactorCost(Type *Ty, GlobalValue *BaseGV, int64_t BaseOffset,
@@ -262,7 +269,7 @@ public:
return -1;
}
- bool isFoldableMemAccessOffset(Instruction *I, int64_t Offset) { return true; }
+ bool LSRWithInstrQueries() { return false; }
bool isTruncateFree(Type *Ty1, Type *Ty2) { return false; }
@@ -288,7 +295,10 @@ public:
bool enableAggressiveInterleaving(bool LoopHasReductions) { return false; }
- bool expandMemCmp(Instruction *I, unsigned &MaxLoadSize) { return false; }
+ const TTI::MemCmpExpansionOptions *enableMemCmpExpansion(
+ bool IsZeroCmp) const {
+ return nullptr;
+ }
bool enableInterleavedAccessVectorization() { return false; }
@@ -306,6 +316,8 @@ public:
bool haveFastSqrt(Type *Ty) { return false; }
+ bool isFCmpOrdCheaperThanFCmpZero(Type *Ty) { return true; }
+
unsigned getFPOpCost(Type *Ty) { return TargetTransformInfo::TCC_Basic; }
int getIntImmCodeSizeCost(unsigned Opcode, unsigned Idx, const APInt &Imm,
@@ -340,6 +352,29 @@ public:
unsigned getCacheLineSize() { return 0; }
+ llvm::Optional<unsigned> getCacheSize(TargetTransformInfo::CacheLevel Level) {
+ switch (Level) {
+ case TargetTransformInfo::CacheLevel::L1D:
+ LLVM_FALLTHROUGH;
+ case TargetTransformInfo::CacheLevel::L2D:
+ return llvm::Optional<unsigned>();
+ }
+
+ llvm_unreachable("Unknown TargetTransformInfo::CacheLevel");
+ }
+
+ llvm::Optional<unsigned> getCacheAssociativity(
+ TargetTransformInfo::CacheLevel Level) {
+ switch (Level) {
+ case TargetTransformInfo::CacheLevel::L1D:
+ LLVM_FALLTHROUGH;
+ case TargetTransformInfo::CacheLevel::L2D:
+ return llvm::Optional<unsigned>();
+ }
+
+ llvm_unreachable("Unknown TargetTransformInfo::CacheLevel");
+ }
+
unsigned getPrefetchDistance() { return 0; }
unsigned getMinPrefetchStride() { return 1; }
@@ -423,10 +458,12 @@ public:
unsigned getAddressComputationCost(Type *Tp, ScalarEvolution *,
const SCEV *) {
- return 0;
+ return 0;
}
- unsigned getReductionCost(unsigned, Type *, bool) { return 1; }
+ unsigned getArithmeticReductionCost(unsigned, Type *, bool) { return 1; }
+
+ unsigned getMinMaxReductionCost(Type *, Type *, bool, bool) { return 1; }
unsigned getCostOfKeepingLiveOverCall(ArrayRef<Type *> Tys) { return 0; }
@@ -587,7 +624,7 @@ protected:
APInt StrideVal = Step->getAPInt();
if (StrideVal.getBitWidth() > 64)
return false;
- // FIXME: need to take absolute value for negtive stride case
+ // FIXME: Need to take absolute value for negative stride case.
return StrideVal.getSExtValue() < MergeDistance;
}
};
@@ -647,11 +684,13 @@ public:
BaseGV = dyn_cast<GlobalValue>(Ptr->stripPointerCasts());
}
bool HasBaseReg = (BaseGV == nullptr);
- int64_t BaseOffset = 0;
+
+ auto PtrSizeBits = DL.getPointerTypeSizeInBits(Ptr->getType());
+ APInt BaseOffset(PtrSizeBits, 0);
int64_t Scale = 0;
auto GTI = gep_type_begin(PointeeType, Operands);
- Type *TargetType;
+ Type *TargetType = nullptr;
// Handle the case where the GEP instruction has a single operand,
// the basis, therefore TargetType is a nullptr.
@@ -673,9 +712,10 @@ public:
BaseOffset += DL.getStructLayout(STy)->getElementOffset(Field);
} else {
int64_t ElementSize = DL.getTypeAllocSize(GTI.getIndexedType());
- if (ConstIdx)
- BaseOffset += ConstIdx->getSExtValue() * ElementSize;
- else {
+ if (ConstIdx) {
+ BaseOffset +=
+ ConstIdx->getValue().sextOrTrunc(PtrSizeBits) * ElementSize;
+ } else {
// Needs scale register.
if (Scale != 0)
// No addressing mode takes two scale registers.
@@ -688,9 +728,10 @@ public:
// Assumes the address space is 0 when Ptr is nullptr.
unsigned AS =
(Ptr == nullptr ? 0 : Ptr->getType()->getPointerAddressSpace());
+
if (static_cast<T *>(this)->isLegalAddressingMode(
- TargetType, const_cast<GlobalValue *>(BaseGV), BaseOffset,
- HasBaseReg, Scale, AS))
+ TargetType, const_cast<GlobalValue *>(BaseGV),
+ BaseOffset.sextOrTrunc(64).getSExtValue(), HasBaseReg, Scale, AS))
return TTI::TCC_Free;
return TTI::TCC_Basic;
}
@@ -713,6 +754,11 @@ public:
if (isa<PHINode>(U))
return TTI::TCC_Free; // Model all PHI nodes as free.
+ // Static alloca doesn't generate target instructions.
+ if (auto *A = dyn_cast<AllocaInst>(U))
+ 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(),
@@ -746,6 +792,38 @@ public:
Operator::getOpcode(U), U->getType(),
U->getNumOperands() == 1 ? U->getOperand(0)->getType() : nullptr);
}
+
+ int getInstructionLatency(const Instruction *I) {
+ SmallVector<const Value *, 4> Operands(I->value_op_begin(),
+ I->value_op_end());
+ if (getUserCost(I, Operands) == TTI::TCC_Free)
+ return 0;
+
+ if (isa<LoadInst>(I))
+ return 4;
+
+ Type *DstTy = I->getType();
+
+ // Usually an intrinsic is a simple instruction.
+ // A real function call is much slower.
+ if (auto *CI = dyn_cast<CallInst>(I)) {
+ const Function *F = CI->getCalledFunction();
+ if (!F || static_cast<T *>(this)->isLoweredToCall(F))
+ return 40;
+ // Some intrinsics return a value and a flag, we use the value type
+ // to decide its latency.
+ if (StructType* StructTy = dyn_cast<StructType>(DstTy))
+ DstTy = StructTy->getElementType(0);
+ // Fall through to simple instructions.
+ }
+
+ if (VectorType *VectorTy = dyn_cast<VectorType>(DstTy))
+ DstTy = VectorTy->getElementType();
+ if (DstTy->isFloatingPointTy())
+ return 3;
+
+ return 1;
+ }
};
}