//
//===----------------------------------------------------------------------===//
+static bool isUsedAsMemCpySource(const Value *V, bool &OtherUse) {
+ bool UsedAsMemCpySource = false;
+ for (const User *U : V->users())
+ if (const Instruction *User = dyn_cast<Instruction>(U)) {
+ if (isa<BitCastInst>(User) || isa<GetElementPtrInst>(User)) {
+ UsedAsMemCpySource |= isUsedAsMemCpySource(User, OtherUse);
+ continue;
+ }
+ if (const MemCpyInst *Memcpy = dyn_cast<MemCpyInst>(User)) {
+ if (Memcpy->getOperand(1) == V && !Memcpy->isVolatile()) {
+ UsedAsMemCpySource = true;
+ continue;
+ }
+ }
+ OtherUse = true;
+ }
+ return UsedAsMemCpySource;
+}
+
+unsigned SystemZTTIImpl::adjustInliningThreshold(const CallBase *CB) const {
+ unsigned Bonus = 0;
+
+ // Increase the threshold if an incoming argument is used only as a memcpy
+ // source.
+ if (Function *Callee = CB->getCalledFunction())
+ for (Argument &Arg : Callee->args()) {
+ bool OtherUse = false;
+ if (isUsedAsMemCpySource(&Arg, OtherUse) && !OtherUse)
+ Bonus += 150;
+ }
+
+ LLVM_DEBUG(if (Bonus)
+ dbgs() << "++ SZTTI Adding inlining bonus: " << Bonus << "\n";);
+ return Bonus;
+}
+
InstructionCost SystemZTTIImpl::getIntImmCost(const APInt &Imm, Type *Ty,
TTI::TargetCostKind CostKind) {
assert(Ty->isIntegerTy());
/// @{
unsigned getInliningThresholdMultiplier() { return 3; }
+ unsigned adjustInliningThreshold(const CallBase *CB) const;
InstructionCost getIntImmCost(const APInt &Imm, Type *Ty,
TTI::TargetCostKind CostKind);
--- /dev/null
+; RUN: opt < %s -mtriple=systemz-unknown -mcpu=z15 -inline -disable-output \
+; RUN: -debug-only=inline,systemztti 2>&1 | FileCheck %s
+; REQUIRES: asserts
+;
+; Check that the inlining threshold is incremented for a function using an
+; argument only as a memcpy source.
+
+; CHECK: Inlining calls in: root_function
+; CHECK: Inlining {{.*}} Call: call void @leaf_function_A(i8* %Dst)
+; CHECK: ++ SZTTI Adding inlining bonus: 150
+; CHECK: Inlining {{.*}} Call: call void @leaf_function_B(i8* %Dst, i8* %Src)
+
+define void @leaf_function_A(i8* %Dst) {
+entry:
+ call void @llvm.memcpy.p0i8.p0i8.i64(i8* %Dst, i8* undef, i64 16, i1 false)
+ ret void
+}
+
+define void @leaf_function_B(i8* %Dst, i8* %Src) {
+entry:
+ call void @llvm.memcpy.p0i8.p0i8.i64(i8* %Dst, i8* %Src, i64 16, i1 false)
+ ret void
+}
+
+define void @root_function(i8* %Dst, i8* %Src) {
+entry:
+ call void @leaf_function_A(i8* %Dst)
+ call void @leaf_function_B(i8* %Dst, i8* %Src)
+ ret void
+}
+
+declare void @llvm.memcpy.p0i8.p0i8.i64(i8* noalias nocapture writeonly, i8* noalias nocapture readonly, i64, i1 immarg)