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