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