blob: b8d284def01f9306c9b46ef83f8af283dc7ab495 [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
Alan Baker0dd3fd22018-08-24 11:03:12 -040022#include "clspv/Option.h"
23
Diego Novilloa4c44fa2019-04-11 10:56:15 -040024#include "ArgKind.h"
25#include "Passes.h"
26
Alan Baker0dd3fd22018-08-24 11:03:12 -040027using namespace llvm;
28
29namespace {
30class InlineFuncWithSingleCallSitePass : public ModulePass {
31public:
32 static char ID;
33 InlineFuncWithSingleCallSitePass() : ModulePass(ID) {}
34
35 bool runOnModule(Module &M) override;
36
37private:
38 bool InlineFunctions(Module &M);
39};
40} // namespace
41
42namespace clspv {
43ModulePass *createInlineFuncWithSingleCallSitePass() {
44 return new InlineFuncWithSingleCallSitePass();
45}
46} // namespace clspv
47
48char InlineFuncWithSingleCallSitePass::ID = 0;
Diego Novilloa4c44fa2019-04-11 10:56:15 -040049INITIALIZE_PASS(InlineFuncWithSingleCallSitePass,
50 "InlineFuncWithSingleCallSite",
51 "Inline functions with a single call site pass", false, false)
Alan Baker0dd3fd22018-08-24 11:03:12 -040052
53bool InlineFuncWithSingleCallSitePass::runOnModule(Module &M) {
54 if (!clspv::Option::InlineSingleCallSite())
55 return false;
56
57 bool Changed = false;
58 for (bool local_changed = true; local_changed; Changed |= local_changed) {
59 local_changed = InlineFunctions(M);
60 }
61
62 // Clean up dead functions. This done here to avoid ordering requirements on
63 // inlining.
64 std::vector<Function *> to_delete;
65 for (auto &F : M) {
66 if (F.isDeclaration() || F.getCallingConv() == CallingConv::SPIR_KERNEL)
67 continue;
68
69 if (F.user_empty())
70 to_delete.push_back(&F);
71 }
72 for (auto func : to_delete) {
73 func->eraseFromParent();
74 }
75
76 return Changed;
77}
78
79bool InlineFuncWithSingleCallSitePass::InlineFunctions(Module &M) {
80 bool Changed = false;
81 std::vector<CallInst *> to_inline;
82 for (auto &F : M) {
83 if (F.isDeclaration() || F.getCallingConv() == CallingConv::SPIR_KERNEL)
84 continue;
85
86 bool has_local_ptr_arg = false;
87 for (auto &Arg : F.args()) {
88 if (clspv::IsLocalPtr(Arg.getType()))
89 has_local_ptr_arg = true;
90 }
91
92 // Only inline if the function has a local address space parameter.
Diego Novillo3cc8d7a2019-04-10 13:30:34 -040093 if (!has_local_ptr_arg)
94 continue;
Alan Baker0dd3fd22018-08-24 11:03:12 -040095
96 if (F.getNumUses() == 1) {
97 if (auto *call = dyn_cast<CallInst>(*F.user_begin()))
98 to_inline.push_back(call);
99 }
100 }
101
102 for (auto call : to_inline) {
103 InlineFunctionInfo IFI;
Alan Baker0dd3fd22018-08-24 11:03:12 -0400104 // Disable generation of lifetime intrinsic.
alan-baker741fd1f2020-04-14 17:38:15 -0400105 Changed |= InlineFunction(*call, IFI, nullptr, false).isSuccess();
Alan Baker0dd3fd22018-08-24 11:03:12 -0400106 }
107
108 return Changed;
109}