summaryrefslogtreecommitdiffstats
path: root/llvm/lib/Analysis/InlineCost.cpp
diff options
context:
space:
mode:
authorNick Desaulniers <ndesaulniers@google.com>2019-05-20 16:48:09 +0000
committerNick Desaulniers <ndesaulniers@google.com>2019-05-20 16:48:09 +0000
commit639b29b1b59f72aa1c713e2edf9410b86872ef32 (patch)
tree81571b33869a2cec2490f4298abb931dbe5c5fa0 /llvm/lib/Analysis/InlineCost.cpp
parent4d05a974b7f15b438cc39fb2b421e35ba6b378b1 (diff)
downloadbcm5719-llvm-639b29b1b59f72aa1c713e2edf9410b86872ef32.tar.gz
bcm5719-llvm-639b29b1b59f72aa1c713e2edf9410b86872ef32.zip
[INLINER] allow inlining of blockaddresses if sole uses are callbrs
Summary: It was supposed that Ref LazyCallGraph::Edge's were being inserted by inlining, but that doesn't seem to be the case. Instead, it seems that there was no test for a blockaddress Constant in an instruction that referenced the function that contained the instruction. Ex: ``` define void @f() { %1 = alloca i8*, align 8 2: store i8* blockaddress(@f, %2), i8** %1, align 8 ret void } ``` When iterating blockaddresses, do not add the function they refer to back to the worklist if the blockaddress is referring to the contained function (as opposed to an external function). Because blockaddress has sligtly different semantics than GNU C's address of labels, there are 3 cases that can occur with blockaddress, where only 1 can happen in GNU C due to C's scoping rules: * blockaddress is within the function it refers to (possible in GNU C). * blockaddress is within a different function than the one it refers to (not possible in GNU C). * blockaddress is used in to declare a global (not possible in GNU C). The second case is tested in: ``` $ ./llvm/build/unittests/Analysis/AnalysisTests \ --gtest_filter=LazyCallGraphTest.HandleBlockAddress ``` This patch adjusts the iteration of blockaddresses in LazyCallGraph::visitReferences to not revisit the blockaddresses function in the first case. The Linux kernel contains code that's not semantically valid at -O0; specifically code passed to asm goto. It requires that asm goto be inline-able. This patch conservatively does not attempt to handle the more general case of inlining blockaddresses that have non-callbr users (pr/39560). https://bugs.llvm.org/show_bug.cgi?id=39560 https://bugs.llvm.org/show_bug.cgi?id=40722 https://github.com/ClangBuiltLinux/linux/issues/6 https://reviews.llvm.org/rL212077 Reviewers: jyknight, eli.friedman, chandlerc Reviewed By: chandlerc Subscribers: george.burgess.iv, nathanchance, mgorny, craig.topper, mengxu.gatech, void, mehdi_amini, E5ten, chandlerc, efriedma, eraman, hiraditya, haicheng, pirama, llvm-commits, srhines Tags: #llvm Differential Revision: https://reviews.llvm.org/D58260 llvm-svn: 361173
Diffstat (limited to 'llvm/lib/Analysis/InlineCost.cpp')
-rw-r--r--llvm/lib/Analysis/InlineCost.cpp27
1 files changed, 17 insertions, 10 deletions
diff --git a/llvm/lib/Analysis/InlineCost.cpp b/llvm/lib/Analysis/InlineCost.cpp
index 62a814914b0..7fcfc76ea62 100644
--- a/llvm/lib/Analysis/InlineCost.cpp
+++ b/llvm/lib/Analysis/InlineCost.cpp
@@ -1830,14 +1830,18 @@ InlineResult CallAnalyzer::analyzeCall(CallBase &Call) {
if (BB->empty())
continue;
- // Disallow inlining a blockaddress. A blockaddress only has defined
- // behavior for an indirect branch in the same function, and we do not
- // currently support inlining indirect branches. But, the inliner may not
- // see an indirect branch that ends up being dead code at a particular call
- // site. If the blockaddress escapes the function, e.g., via a global
- // variable, inlining may lead to an invalid cross-function reference.
+ // Disallow inlining a blockaddress with uses other than strictly callbr.
+ // A blockaddress only has defined behavior for an indirect branch in the
+ // same function, and we do not currently support inlining indirect
+ // branches. But, the inliner may not see an indirect branch that ends up
+ // being dead code at a particular call site. If the blockaddress escapes
+ // the function, e.g., via a global variable, inlining may lead to an
+ // invalid cross-function reference.
+ // FIXME: pr/39560: continue relaxing this overt restriction.
if (BB->hasAddressTaken())
- return "blockaddress";
+ for (User *U : BlockAddress::get(&*BB)->users())
+ if (!isa<CallBrInst>(*U))
+ return "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.
@@ -2081,13 +2085,16 @@ InlineCost llvm::getInlineCost(
InlineResult llvm::isInlineViable(Function &F) {
bool ReturnsTwice = F.hasFnAttribute(Attribute::ReturnsTwice);
for (Function::iterator BI = F.begin(), BE = F.end(); BI != BE; ++BI) {
- // Disallow inlining of functions which contain indirect branches or
- // blockaddresses.
+ // Disallow inlining of functions which contain indirect branches.
if (isa<IndirectBrInst>(BI->getTerminator()))
return "contains indirect branches";
+ // Disallow inlining of blockaddresses which are used by non-callbr
+ // instructions.
if (BI->hasAddressTaken())
- return "uses block address";
+ for (User *U : BlockAddress::get(&*BI)->users())
+ if (!isa<CallBrInst>(*U))
+ return "blockaddress used outside of callbr";
for (auto &II : *BI) {
CallBase *Call = dyn_cast<CallBase>(&II);
OpenPOWER on IntegriCloud