Index: llvm/lib/Analysis/InlineCost.cpp =================================================================== --- llvm/lib/Analysis/InlineCost.cpp +++ llvm/lib/Analysis/InlineCost.cpp @@ -1570,6 +1570,12 @@ return false; } +/// Return Result1 if it is negative, otherwise return Result2. +static InlineResult GetFirstNegative(const InlineResult &Result1, + const InlineResult &Result2) { + return Result1 ? Result2 : Result1; +} + /// Analyze a basic block for its contribution to the inline cost. /// /// This method walks the analyzer over every instruction in the given basic @@ -1580,6 +1586,8 @@ InlineResult CallAnalyzer::analyzeBlock(BasicBlock *BB, SmallPtrSetImpl &EphValues) { + InlineResult Result = true; + for (BasicBlock::iterator I = BB->begin(), E = BB->end(); I != E; ++I) { // FIXME: Currently, the number of instructions in a function regardless of // our ability to simplify them during inline to constants or dead code, @@ -1633,7 +1641,7 @@ << NV("InlineResult", IR.message) << ") and cost is not fully computed"; }); - return IR; + return GetFirstNegative(Result, IR); } // If the caller is a recursive function then we don't want to inline @@ -1649,16 +1657,19 @@ << NV("Callee", &F) << " is " << NV("InlineResult", IR.message) << ". Cost is not fully computed"; }); - return IR; + return GetFirstNegative(Result, IR); } // Check if we've passed the maximum possible threshold so we don't spin in // huge basic blocks that will never inline. - if (Cost >= Threshold && !ComputeFullInlineCost) - return false; + if (Cost >= Threshold) { + if (!ComputeFullInlineCost) + return false; + Result = false; + } } - return true; + return Result; } /// Compute the base pointer and cumulative constant offsets for V. @@ -1785,12 +1796,17 @@ if (F.getCallingConv() == CallingConv::Cold) Cost += InlineConstants::ColdccPenalty; + InlineResult Result = true; + // Check if we're done. This can happen due to bonuses and penalties. - if (Cost >= Threshold && !ComputeFullInlineCost) - return "high cost"; + if (Cost >= Threshold) { + Result = "high cost"; + if (!ComputeFullInlineCost) + return Result; + } if (F.empty()) - return true; + return GetFirstNegative(Result, true); Function *Caller = Call.getFunction(); // Check if the caller function is recursive itself. @@ -1849,8 +1865,11 @@ for (unsigned Idx = 0; Idx != BBWorklist.size(); ++Idx) { // Bail out the moment we cross the threshold. This means we'll under-count // the cost, but only when undercounting doesn't matter. - if (Cost >= Threshold && !ComputeFullInlineCost) - break; + if (Cost >= Threshold) { + Result = GetFirstNegative(Result, InlineResult(false)); + if (!ComputeFullInlineCost) + break; + } BasicBlock *BB = BBWorklist[Idx]; if (BB->empty()) @@ -1867,13 +1886,13 @@ if (BB->hasAddressTaken()) for (User *U : BlockAddress::get(&*BB)->users()) if (!isa(*U)) - return "blockaddress used outside of callbr"; + return GetFirstNegative(Result, "blockaddress used outside of callbr"); // Analyze the cost of this block. If we blow through the threshold, this // returns false, and we can bail on out. InlineResult IR = analyzeBlock(BB, EphValues); if (!IR) - return IR; + return GetFirstNegative(Result, IR); Instruction *TI = BB->getTerminator(); @@ -1926,7 +1945,7 @@ // inlining this would cause the removal of the caller (so the instruction // is not actually duplicated, just moved). if (!OnlyOneCallAndLocalLinkage && ContainsNoDuplicateCall) - return "noduplicate"; + return GetFirstNegative(Result, "noduplicate"); // Loops generally act a lot like calls in that they act like barriers to // movement, require a certain amount of setup, etc. So when optimising for @@ -1954,7 +1973,7 @@ else if (NumVectorInstructions <= NumInstructions / 2) Threshold -= VectorBonus/2; - return Cost < std::max(1, Threshold); + return GetFirstNegative(Result, Cost < std::max(1, Threshold)); } #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) Index: llvm/test/Transforms/Inline/inline_negative_result.ll =================================================================== --- llvm/test/Transforms/Inline/inline_negative_result.ll +++ llvm/test/Transforms/Inline/inline_negative_result.ll @@ -1,14 +1,17 @@ -; NOTE: Assertions have been autogenerated by utils/update_test_checks.py -; RUN: opt < %s -inline -S | FileCheck %s +; RUN: opt < %s -inline -S -inline-remark-attribute | FileCheck %s +; RUN: opt < %s -inline -S -inline-remark-attribute --pass-remarks-missed=inline --pass-remarks-analysis=inline --pass-remarks=inline | FileCheck %s +; RUN: opt < %s -inline -S -inline-remark-attribute -inline-cost-full=true | FileCheck %s +; RUN: opt < %s -inline -S -inline-remark-attribute -inline-cost-full=false | FileCheck %s ; PR42084 +; The test checks that inline remarks do not change inline decisions. define internal fastcc void @func4() { ; CHECK-LABEL: @func4( ; CHECK-NEXT: entry: ; CHECK-NEXT: br label [[FOR_COND:%.*]] ; CHECK: for.cond: -; CHECK-NEXT: tail call void (...) @g() +; CHECK-NEXT: tail call void (...) @g() [[INLINE_REMARK0:#[0-9]+]] ; CHECK-NEXT: br label [[FOR_COND]] ; entry: @@ -22,7 +25,7 @@ define internal fastcc void @func3() { ; CHECK-LABEL: @func3( ; CHECK-NEXT: entry: -; CHECK-NEXT: tail call fastcc void @func4() +; CHECK-NEXT: tail call fastcc void @func4() [[INLINE_REMARK1:#[0-9]+]] ; CHECK-NEXT: unreachable ; entry: @@ -33,7 +36,7 @@ define internal fastcc void @func2() { ; CHECK-LABEL: @func2( ; CHECK-NEXT: entry: -; CHECK-NEXT: tail call fastcc void @func3() +; CHECK-NEXT: tail call fastcc void @func3() [[INLINE_REMARK1:#[0-9]+]] ; CHECK-NEXT: unreachable ; entry: @@ -44,7 +47,7 @@ define internal fastcc void @func1() { ; CHECK-LABEL: @func1( ; CHECK-NEXT: entry: -; CHECK-NEXT: tail call fastcc void @func2() +; CHECK-NEXT: tail call fastcc void @func2() [[INLINE_REMARK1:#[0-9]+]] ; CHECK-NEXT: unreachable ; entry: @@ -55,7 +58,7 @@ define i32 @main() { ; CHECK-LABEL: @main( ; CHECK-NEXT: entry: -; CHECK-NEXT: tail call fastcc void @func1() +; CHECK-NEXT: tail call fastcc void @func1() [[INLINE_REMARK1:#[0-9]+]] ; CHECK-NEXT: unreachable ; entry: @@ -64,3 +67,6 @@ } declare void @g(...) + +; CHECK: attributes [[INLINE_REMARK0]] = { "inline-remark"="unavailable definition" } +; CHECK: attributes [[INLINE_REMARK1]] = { "inline-remark"="(cost=0, threshold=0)" }