blob: 951e8abe83d9c5f4b41cc15d30132d4b73fe6345 [file] [log] [blame]
David Neto90138b72018-05-28 14:57:09 -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 "llvm/ADT/UniqueVector.h"
16#include "llvm/IR/Instructions.h"
17#include "llvm/IR/Module.h"
18#include "llvm/Pass.h"
19#include "llvm/Support/raw_ostream.h"
20#include "llvm/Transforms/Utils/Cloning.h"
21
22#include "clspv/AddressSpace.h"
23
24using namespace llvm;
25
26#define DEBUG_TYPE "inlinefuncwithpointerfunctionarg"
27
28namespace {
29struct InlineFuncWithPointerToFunctionArgPass : public ModulePass {
30 static char ID;
31 InlineFuncWithPointerToFunctionArgPass() : ModulePass(ID) {}
32
33 bool InlineFunctions(Module &M);
34 bool runOnModule(Module &M) override;
35};
36
37// Returns true if |type| is a pointer to Function storage class.
38bool IsPointerToFunctionStorage(Type *type) {
39 if (auto *pointerTy = dyn_cast<PointerType>(type)) {
40 return pointerTy->getAddressSpace() == clspv::AddressSpace::Private;
41 }
42 return false;
43}
44
45// Returns true if |type| is a function whose return type or any of its
46// arguments are pointer-to-Function storage class.
47bool IsProblematicFunctionType(Type *type) {
48 if (auto *funcTy = dyn_cast<FunctionType>(type)) {
49 if (IsPointerToFunctionStorage(funcTy->getReturnType())) {
50 return true;
51 }
52 for (auto *paramTy : funcTy->params()) {
53 if (IsPointerToFunctionStorage(paramTy)) {
54 return true;
55 }
56 }
57 }
58 return false;
59}
60} // namespace
61
62char InlineFuncWithPointerToFunctionArgPass::ID = 0;
63static RegisterPass<InlineFuncWithPointerToFunctionArgPass>
64 X("InlineFuncWithPointerToFunctionArgPass",
65 "Inline Function with Pointer-to-Function storage Argument Pass");
66
67namespace clspv {
68llvm::ModulePass *createInlineFuncWithPointerToFunctionArgPass() {
69 return new InlineFuncWithPointerToFunctionArgPass();
70}
71} // namespace clspv
72
73bool InlineFuncWithPointerToFunctionArgPass::runOnModule(Module &M) {
74 bool Changed = false;
75
76 // Loop through our inline pass until they stop changing thing.
77 for (bool localChanged = true; localChanged; Changed |= localChanged) {
78 localChanged = false;
79
80 localChanged |= InlineFunctions(M);
81 }
82
83 return Changed;
84}
85
86bool InlineFuncWithPointerToFunctionArgPass::InlineFunctions(Module &M) {
87 bool Changed = false;
88
89 UniqueVector<CallInst *> WorkList;
90 for (Function &F : M) {
91 for (BasicBlock &BB : F) {
92 for (Instruction &I : BB) {
93 if (auto call = dyn_cast<CallInst>(&I)) {
94 if (IsProblematicFunctionType(call->getFunctionType())) {
95 WorkList.insert(call);
96 }
97 }
98 }
99 }
100 }
101
102 for (CallInst *Call : WorkList) {
103 InlineFunctionInfo IFI;
104 CallSite CS(Call);
105 // Disable generation of lifetime intrinsic.
106 Changed |= InlineFunction(CS, IFI, nullptr, false);
107 }
108
109 // Remove dead functions.
110 bool removed;
111 do {
112 removed = false;
113 for (auto &F : M) {
114 if (F.getCallingConv() == CallingConv::SPIR_KERNEL)
115 continue;
116 if (F.use_begin() == F.use_end()) {
117 F.eraseFromParent();
118 removed = true;
119 Changed = true;
120 break;
121 }
122 }
123 } while (removed);
124
125 return Changed;
126}