blob: 5759e755dc89226fb56b196a3944f5fe4d882c5c [file] [log] [blame]
Alan Baker0dd3fd22018-08-24 11:03:12 -04001// Copyright 2018 The Clspv Authors. All rights reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#include <vector>
16
17#include "llvm/IR/CallingConv.h"
18#include "llvm/Pass.h"
19#include "llvm/Support/raw_ostream.h"
20#include "llvm/Transforms/Utils/Cloning.h"
21
22#include "ArgKind.h"
23#include "clspv/Option.h"
24
25using namespace llvm;
26
27namespace {
28class InlineFuncWithSingleCallSitePass : public ModulePass {
29public:
30 static char ID;
31 InlineFuncWithSingleCallSitePass() : ModulePass(ID) {}
32
33 bool runOnModule(Module &M) override;
34
35private:
36 bool InlineFunctions(Module &M);
37};
38} // namespace
39
40namespace clspv {
41ModulePass *createInlineFuncWithSingleCallSitePass() {
42 return new InlineFuncWithSingleCallSitePass();
43}
44} // namespace clspv
45
46char InlineFuncWithSingleCallSitePass::ID = 0;
47static RegisterPass<InlineFuncWithSingleCallSitePass>
48 X("InlineFuncWithSingleCallSite",
49 "Inline functions with a single call site pass");
50
51bool InlineFuncWithSingleCallSitePass::runOnModule(Module &M) {
52 if (!clspv::Option::InlineSingleCallSite())
53 return false;
54
55 bool Changed = false;
56 for (bool local_changed = true; local_changed; Changed |= local_changed) {
57 local_changed = InlineFunctions(M);
58 }
59
60 // Clean up dead functions. This done here to avoid ordering requirements on
61 // inlining.
62 std::vector<Function *> to_delete;
63 for (auto &F : M) {
64 if (F.isDeclaration() || F.getCallingConv() == CallingConv::SPIR_KERNEL)
65 continue;
66
67 if (F.user_empty())
68 to_delete.push_back(&F);
69 }
70 for (auto func : to_delete) {
71 func->eraseFromParent();
72 }
73
74 return Changed;
75}
76
77bool InlineFuncWithSingleCallSitePass::InlineFunctions(Module &M) {
78 bool Changed = false;
79 std::vector<CallInst *> to_inline;
80 for (auto &F : M) {
81 if (F.isDeclaration() || F.getCallingConv() == CallingConv::SPIR_KERNEL)
82 continue;
83
84 bool has_local_ptr_arg = false;
85 for (auto &Arg : F.args()) {
86 if (clspv::IsLocalPtr(Arg.getType()))
87 has_local_ptr_arg = true;
88 }
89
90 // Only inline if the function has a local address space parameter.
Diego Novillo3cc8d7a2019-04-10 13:30:34 -040091 if (!has_local_ptr_arg)
92 continue;
Alan Baker0dd3fd22018-08-24 11:03:12 -040093
94 if (F.getNumUses() == 1) {
95 if (auto *call = dyn_cast<CallInst>(*F.user_begin()))
96 to_inline.push_back(call);
97 }
98 }
99
100 for (auto call : to_inline) {
101 InlineFunctionInfo IFI;
102 CallSite CS(call);
103 // Disable generation of lifetime intrinsic.
104 Changed |= InlineFunction(CS, IFI, nullptr, false);
105 }
106
107 return Changed;
108}