Skip to content
This repository was archived by the owner on Apr 23, 2020. It is now read-only.

Commit b699f7b

Browse files
committed
[PM] Port the always inliner to the new pass manager in a much more
minimal and boring form than the old pass manager's version. This pass does the very minimal amount of work necessary to inline functions declared as always-inline. It doesn't support a wide array of things that the legacy pass manager did support, but is alse ... about 20 lines of code. So it has that going for it. Notably things this doesn't support: - Array alloca merging - To support the above, bottom-up inlining with careful history tracking and call graph updates - DCE of the functions that become dead after this inlining. - Inlining through call instructions with the always_inline attribute. Instead, it focuses on inlining functions with that attribute. The first I've omitted because I'm hoping to just turn it off for the primary pass manager. If that doesn't pan out, I can add it here but it will be reasonably expensive to do so. The second should really be handled by running global-dce after the inliner. I don't want to re-implement the non-trivial logic necessary to do comdat-correct DCE of functions. This means the -O0 pipeline will have to be at least 'always-inline,global-dce', but that seems reasonable to me. If others are seriously worried about this I'd like to hear about it and understand why. Again, this is all solveable by factoring that logic into a utility and calling it here, but I'd like to wait to do that until there is a clear reason why the existing pass-based factoring won't work. The final point is a serious one. I can fairly easily add support for this, but it seems both costly and a confusing construct for the use case of the always inliner running at -O0. This attribute can of course still impact the normal inliner easily (although I find that a questionable re-use of the same attribute). I've started a discussion to sort out what semantics we want here and based on that can figure out if it makes sense ta have this complexity at O0 or not. One other advantage of this design is that it should be quite a bit faster due to checking for whether the function is a viable candidate for inlining exactly once per function instead of doing it for each call site. Anyways, hopefully a reasonable starting point for this pass. Differential Revision: https://reviews.llvm.org/D23299 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@278896 91177308-0d34-0410-b5e6-96231b3b80d8
1 parent be01ee2 commit b699f7b

File tree

14 files changed

+120
-37
lines changed

14 files changed

+120
-37
lines changed

include/llvm/InitializePasses.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ void initializeAddressSanitizerModulePass(PassRegistry&);
6666
void initializeAddressSanitizerPass(PassRegistry&);
6767
void initializeAliasSetPrinterPass(PassRegistry&);
6868
void initializeAlignmentFromAssumptionsPass(PassRegistry&);
69-
void initializeAlwaysInlinerPass(PassRegistry&);
69+
void initializeAlwaysInlinerLegacyPassPass(PassRegistry&);
7070
void initializeArgPromotionPass(PassRegistry&);
7171
void initializeAssumptionCacheTrackerPass(PassRegistry &);
7272
void initializeAtomicExpandPass(PassRegistry&);

include/llvm/LinkAllPasses.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
#include "llvm/IR/Function.h"
4040
#include "llvm/IR/IRPrintingPasses.h"
4141
#include "llvm/Transforms/IPO.h"
42+
#include "llvm/Transforms/IPO/AlwaysInliner.h"
4243
#include "llvm/Transforms/IPO/FunctionAttrs.h"
4344
#include "llvm/Transforms/Instrumentation.h"
4445
#include "llvm/Transforms/ObjCARC.h"
@@ -97,7 +98,7 @@ namespace {
9798
(void) llvm::createInstrProfilingLegacyPass();
9899
(void) llvm::createFunctionImportPass();
99100
(void) llvm::createFunctionInliningPass();
100-
(void) llvm::createAlwaysInlinerPass();
101+
(void) llvm::createAlwaysInlinerLegacyPass();
101102
(void) llvm::createGlobalDCEPass();
102103
(void) llvm::createGlobalOptimizerPass();
103104
(void) llvm::createGlobalsAAWrapperPass();

include/llvm/Transforms/IPO.h

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -106,12 +106,6 @@ Pass *createFunctionInliningPass(int Threshold);
106106
Pass *createFunctionInliningPass(unsigned OptLevel, unsigned SizeOptLevel);
107107
Pass *createFunctionInliningPass(InlineParams &Params);
108108

109-
//===----------------------------------------------------------------------===//
110-
/// createAlwaysInlinerPass - Return a new pass object that inlines only
111-
/// functions that are marked as "always_inline".
112-
Pass *createAlwaysInlinerPass();
113-
Pass *createAlwaysInlinerPass(bool InsertLifetime);
114-
115109
//===----------------------------------------------------------------------===//
116110
/// createPruneEHPass - Return a new pass object which transforms invoke
117111
/// instructions into calls, if the callee can _not_ unwind the stack.
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
//===-- AlwaysInliner.h - Pass to inline "always_inline" functions --------===//
2+
//
3+
// The LLVM Compiler Infrastructure
4+
//
5+
// This file is distributed under the University of Illinois Open Source
6+
// License. See LICENSE.TXT for details.
7+
//
8+
//===----------------------------------------------------------------------===//
9+
///
10+
/// \file
11+
/// Provides passes to inlining "always_inline" functions.
12+
///
13+
//===----------------------------------------------------------------------===//
14+
15+
#ifndef LLVM_TRANSFORMS_IPO_ALWAYSINLINER_H
16+
#define LLVM_TRANSFORMS_IPO_ALWAYSINLINER_H
17+
18+
#include "llvm/IR/PassManager.h"
19+
20+
namespace llvm {
21+
22+
/// Inlines functions marked as "always_inline".
23+
///
24+
/// Note that this does not inline call sites marked as always_inline and does
25+
/// not delete the functions even when all users are inlined. The normal
26+
/// inliner should be used to handle call site inlining, this pass's goal is to
27+
/// be the simplest possible pass to remove always_inline function definitions'
28+
/// uses by inlining them. The \c GlobalDCE pass can be used to remove these
29+
/// functions once all users are gone.
30+
struct AlwaysInlinerPass : PassInfoMixin<AlwaysInlinerPass> {
31+
PreservedAnalyses run(Module &M, ModuleAnalysisManager &);
32+
};
33+
34+
/// Create a legacy pass manager instance of a pass to inline and remove
35+
/// functions marked as "always_inline".
36+
Pass *createAlwaysInlinerLegacyPass(bool InsertLifetime = true);
37+
38+
}
39+
40+
#endif // LLVM_TRANSFORMS_IPO_ALWAYSINLINER_H

lib/Passes/PassBuilder.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@
5959
#include "llvm/Support/Regex.h"
6060
#include "llvm/Target/TargetMachine.h"
6161
#include "llvm/Transforms/GCOVProfiler.h"
62+
#include "llvm/Transforms/IPO/AlwaysInliner.h"
6263
#include "llvm/Transforms/IPO/ConstantMerge.h"
6364
#include "llvm/Transforms/IPO/CrossDSOCFI.h"
6465
#include "llvm/Transforms/IPO/DeadArgumentElimination.h"

lib/Passes/PassRegistry.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ MODULE_ALIAS_ANALYSIS("globals-aa", GlobalsAA())
3838
#ifndef MODULE_PASS
3939
#define MODULE_PASS(NAME, CREATE_PASS)
4040
#endif
41+
MODULE_PASS("always-inline", AlwaysInlinerPass())
4142
MODULE_PASS("constmerge", ConstantMergePass())
4243
MODULE_PASS("cross-dso-cfi", CrossDSOCFIPass())
4344
MODULE_PASS("deadargelim", DeadArgumentEliminationPass())

lib/Target/AMDGPU/AMDGPUTargetMachine.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#include "llvm/CodeGen/TargetPassConfig.h"
3030
#include "llvm/Support/TargetRegistry.h"
3131
#include "llvm/Transforms/IPO.h"
32+
#include "llvm/Transforms/IPO/AlwaysInliner.h"
3233
#include "llvm/Transforms/Scalar.h"
3334
#include "llvm/Transforms/Scalar/GVN.h"
3435
#include "llvm/Transforms/Vectorize.h"
@@ -360,7 +361,7 @@ void AMDGPUPassConfig::addIRPasses() {
360361

361362
// Function calls are not supported, so make sure we inline everything.
362363
addPass(createAMDGPUAlwaysInlinePass());
363-
addPass(createAlwaysInlinerPass());
364+
addPass(createAlwaysInlinerLegacyPass());
364365
// We need to add the barrier noop pass, otherwise adding the function
365366
// inlining pass will cause all of the PassConfigs passes to be run
366367
// one function at a time, which means if we have a nodule with two

lib/Transforms/IPO/InlineAlways.cpp renamed to lib/Transforms/IPO/AlwaysInliner.cpp

Lines changed: 41 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@
1212
//
1313
//===----------------------------------------------------------------------===//
1414

15-
#include "llvm/ADT/SmallPtrSet.h"
15+
#include "llvm/Transforms/IPO/AlwaysInliner.h"
16+
#include "llvm/ADT/SetVector.h"
1617
#include "llvm/Analysis/AssumptionCache.h"
1718
#include "llvm/Analysis/CallGraph.h"
1819
#include "llvm/Analysis/InlineCost.h"
@@ -25,25 +26,51 @@
2526
#include "llvm/IR/IntrinsicInst.h"
2627
#include "llvm/IR/Module.h"
2728
#include "llvm/IR/Type.h"
28-
#include "llvm/Transforms/IPO.h"
2929
#include "llvm/Transforms/IPO/InlinerPass.h"
30+
#include "llvm/Transforms/Utils/Cloning.h"
3031

3132
using namespace llvm;
3233

3334
#define DEBUG_TYPE "inline"
3435

36+
PreservedAnalyses AlwaysInlinerPass::run(Module &M, ModuleAnalysisManager &) {
37+
InlineFunctionInfo IFI;
38+
SmallSetVector<CallSite, 16> Calls;
39+
bool Changed = false;
40+
for (Function &F : M)
41+
if (!F.isDeclaration() && F.hasFnAttribute(Attribute::AlwaysInline) &&
42+
isInlineViable(F)) {
43+
Calls.clear();
44+
45+
for (User *U : F.users())
46+
if (auto CS = CallSite(U))
47+
if (CS.getCalledFunction() == &F)
48+
Calls.insert(CS);
49+
50+
for (CallSite CS : Calls)
51+
// FIXME: We really shouldn't be able to fail to inline at this point!
52+
// We should do something to log or check the inline failures here.
53+
Changed |= InlineFunction(CS, IFI);
54+
}
55+
56+
return Changed ? PreservedAnalyses::none() : PreservedAnalyses::all();
57+
}
58+
3559
namespace {
3660

37-
/// \brief Inliner pass which only handles "always inline" functions.
38-
class AlwaysInliner : public Inliner {
61+
/// Inliner pass which only handles "always inline" functions.
62+
///
63+
/// Unlike the \c AlwaysInlinerPass, this uses the more heavyweight \c Inliner
64+
/// base class to provide several facilities such as array alloca merging.
65+
class AlwaysInlinerLegacyPass : public Inliner {
3966

4067
public:
41-
AlwaysInliner() : Inliner(ID, /*InsertLifetime*/ true) {
42-
initializeAlwaysInlinerPass(*PassRegistry::getPassRegistry());
68+
AlwaysInlinerLegacyPass() : Inliner(ID, /*InsertLifetime*/ true) {
69+
initializeAlwaysInlinerLegacyPassPass(*PassRegistry::getPassRegistry());
4370
}
4471

45-
AlwaysInliner(bool InsertLifetime) : Inliner(ID, InsertLifetime) {
46-
initializeAlwaysInlinerPass(*PassRegistry::getPassRegistry());
72+
AlwaysInlinerLegacyPass(bool InsertLifetime) : Inliner(ID, InsertLifetime) {
73+
initializeAlwaysInlinerLegacyPassPass(*PassRegistry::getPassRegistry());
4774
}
4875

4976
/// Main run interface method. We override here to avoid calling skipSCC().
@@ -60,20 +87,18 @@ class AlwaysInliner : public Inliner {
6087
};
6188
}
6289

63-
char AlwaysInliner::ID = 0;
64-
INITIALIZE_PASS_BEGIN(AlwaysInliner, "always-inline",
90+
char AlwaysInlinerLegacyPass::ID = 0;
91+
INITIALIZE_PASS_BEGIN(AlwaysInlinerLegacyPass, "always-inline",
6592
"Inliner for always_inline functions", false, false)
6693
INITIALIZE_PASS_DEPENDENCY(AssumptionCacheTracker)
6794
INITIALIZE_PASS_DEPENDENCY(CallGraphWrapperPass)
6895
INITIALIZE_PASS_DEPENDENCY(ProfileSummaryInfoWrapperPass)
6996
INITIALIZE_PASS_DEPENDENCY(TargetLibraryInfoWrapperPass)
70-
INITIALIZE_PASS_END(AlwaysInliner, "always-inline",
97+
INITIALIZE_PASS_END(AlwaysInlinerLegacyPass, "always-inline",
7198
"Inliner for always_inline functions", false, false)
7299

73-
Pass *llvm::createAlwaysInlinerPass() { return new AlwaysInliner(); }
74-
75-
Pass *llvm::createAlwaysInlinerPass(bool InsertLifetime) {
76-
return new AlwaysInliner(InsertLifetime);
100+
Pass *llvm::createAlwaysInlinerLegacyPass(bool InsertLifetime) {
101+
return new AlwaysInlinerLegacyPass(InsertLifetime);
77102
}
78103

79104
/// \brief Get the inline cost for the always-inliner.
@@ -88,7 +113,7 @@ Pass *llvm::createAlwaysInlinerPass(bool InsertLifetime) {
88113
/// computed here, but as we only expect to do this for relatively few and
89114
/// small functions which have the explicit attribute to force inlining, it is
90115
/// likely not worth it in practice.
91-
InlineCost AlwaysInliner::getInlineCost(CallSite CS) {
116+
InlineCost AlwaysInlinerLegacyPass::getInlineCost(CallSite CS) {
92117
Function *Callee = CS.getCalledFunction();
93118

94119
// Only inline direct calls to functions with always-inline attributes

lib/Transforms/IPO/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
add_llvm_library(LLVMipo
2+
AlwaysInliner.cpp
23
ArgumentPromotion.cpp
34
BarrierNoopPass.cpp
45
ConstantMerge.cpp
@@ -14,7 +15,6 @@ add_llvm_library(LLVMipo
1415
IPConstantPropagation.cpp
1516
IPO.cpp
1617
InferFunctionAttrs.cpp
17-
InlineAlways.cpp
1818
InlineSimple.cpp
1919
Inliner.cpp
2020
Internalize.cpp

lib/Transforms/IPO/IPO.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include "llvm/InitializePasses.h"
1919
#include "llvm/IR/LegacyPassManager.h"
2020
#include "llvm/Transforms/IPO.h"
21+
#include "llvm/Transforms/IPO/AlwaysInliner.h"
2122
#include "llvm/Transforms/IPO/FunctionAttrs.h"
2223

2324
using namespace llvm;
@@ -32,7 +33,7 @@ void llvm::initializeIPO(PassRegistry &Registry) {
3233
initializeGlobalDCELegacyPassPass(Registry);
3334
initializeGlobalOptLegacyPassPass(Registry);
3435
initializeIPCPPass(Registry);
35-
initializeAlwaysInlinerPass(Registry);
36+
initializeAlwaysInlinerLegacyPassPass(Registry);
3637
initializeSimpleInlinerPass(Registry);
3738
initializeInferFunctionAttrsLegacyPassPass(Registry);
3839
initializeInternalizeLegacyPassPass(Registry);
@@ -82,7 +83,7 @@ void LLVMAddFunctionInliningPass(LLVMPassManagerRef PM) {
8283
}
8384

8485
void LLVMAddAlwaysInlinerPass(LLVMPassManagerRef PM) {
85-
unwrap(PM)->add(llvm::createAlwaysInlinerPass());
86+
unwrap(PM)->add(llvm::createAlwaysInlinerLegacyPass());
8687
}
8788

8889
void LLVMAddGlobalDCEPass(LLVMPassManagerRef PM) {

lib/Transforms/Utils/InlineFunction.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1053,7 +1053,7 @@ static void AddAliasScopeMetadata(CallSite CS, ValueToValueMapTy &VMap,
10531053
/// If the inlined function has non-byval align arguments, then
10541054
/// add @llvm.assume-based alignment assumptions to preserve this information.
10551055
static void AddAlignmentAssumptions(CallSite CS, InlineFunctionInfo &IFI) {
1056-
if (!PreserveAlignmentAssumptions)
1056+
if (!PreserveAlignmentAssumptions || !IFI.GetAssumptionCache)
10571057
return;
10581058
AssumptionCache *AC = IFI.GetAssumptionCache
10591059
? &(*IFI.GetAssumptionCache)(*CS.getCaller())

test/Transforms/Inline/always-inline.ll

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
1-
; RUN: opt < %s -inline-threshold=0 -always-inline -S | FileCheck %s
1+
; RUN: opt < %s -inline-threshold=0 -always-inline -S | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-CALL
22
;
33
; Ensure the threshold has no impact on these decisions.
4-
; RUN: opt < %s -inline-threshold=20000000 -always-inline -S | FileCheck %s
5-
; RUN: opt < %s -inline-threshold=-20000000 -always-inline -S | FileCheck %s
4+
; RUN: opt < %s -inline-threshold=20000000 -always-inline -S | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-CALL
5+
; RUN: opt < %s -inline-threshold=-20000000 -always-inline -S | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-CALL
6+
;
7+
; The new pass manager doesn't re-use any threshold based infrastructure for
8+
; the always inliner, but test that we get the correct result.
9+
; RUN: opt < %s -passes=always-inline -S | FileCheck %s --check-prefix=CHECK
610

711
define i32 @inner1() alwaysinline {
812
ret i32 1
@@ -126,10 +130,23 @@ define i32 @inner7() {
126130
ret i32 1
127131
}
128132
define i32 @outer7() {
129-
; CHECK-LABEL: @outer7(
130-
; CHECK-NOT: call
131-
; CHECK: ret
133+
; CHECK-CALL-LABEL: @outer7(
134+
; CHECK-CALL-NOT: call
135+
; CHECK-CALL: ret
132136

133137
%r = call i32 @inner7() alwaysinline
134138
ret i32 %r
135139
}
140+
141+
define float* @inner8(float* nocapture align 128 %a) alwaysinline {
142+
ret float* %a
143+
}
144+
define float @outer8(float* nocapture %a) {
145+
; CHECK-LABEL: @outer8(
146+
; CHECK-NOT: call float* @inner8
147+
; CHECK: ret
148+
149+
%inner_a = call float* @inner8(float* %a)
150+
%f = load float, float* %inner_a, align 4
151+
ret float %f
152+
}

tools/bugpoint/bugpoint.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include "llvm/Support/Process.h"
2828
#include "llvm/Support/Signals.h"
2929
#include "llvm/Support/Valgrind.h"
30+
#include "llvm/Transforms/IPO/AlwaysInliner.h"
3031
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
3132

3233
//Enable this macro to debug bugpoint itself.
@@ -179,7 +180,7 @@ int main(int argc, char **argv) {
179180
if (OptLevelO1 || OptLevelO2 || OptLevelO3) {
180181
PassManagerBuilder Builder;
181182
if (OptLevelO1)
182-
Builder.Inliner = createAlwaysInlinerPass();
183+
Builder.Inliner = createAlwaysInlinerLegacyPass();
183184
else if (OptLevelOs || OptLevelO2)
184185
Builder.Inliner = createFunctionInliningPass(2, OptLevelOs ? 1 : 0);
185186
else

tools/opt/opt.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
#include "llvm/Support/ToolOutputFile.h"
5252
#include "llvm/Target/TargetMachine.h"
5353
#include "llvm/Transforms/Coroutines.h"
54+
#include "llvm/Transforms/IPO/AlwaysInliner.h"
5455
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
5556
#include "llvm/Transforms/Utils/Cloning.h"
5657
#include <algorithm>
@@ -259,7 +260,7 @@ static void AddOptimizationPasses(legacy::PassManagerBase &MPM,
259260
} else if (OptLevel > 1) {
260261
Builder.Inliner = createFunctionInliningPass(OptLevel, SizeLevel);
261262
} else {
262-
Builder.Inliner = createAlwaysInlinerPass();
263+
Builder.Inliner = createAlwaysInlinerLegacyPass();
263264
}
264265
Builder.DisableUnitAtATime = !UnitAtATime;
265266
Builder.DisableUnrollLoops = (DisableLoopUnrolling.getNumOccurrences() > 0) ?

0 commit comments

Comments
 (0)