1/*
2 * Copyright 2017, The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *     http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "GlobalAllocPass.h"
18
19#include "Context.h"
20#include "RSAllocationUtils.h"
21
22#include "llvm/IR/GlobalVariable.h"
23#include "llvm/IR/Module.h"
24#include "llvm/Pass.h"
25#include "llvm/Support/Debug.h"
26
27#define DEBUG_TYPE "rs2spirv-global-alloc"
28
29using namespace llvm;
30
31namespace rs2spirv {
32
33namespace {
34bool collectGlobalAllocs(Module &M,
35                         SmallVectorImpl<GlobalVariable *> &GlobalAllocs) {
36  for (auto &GV : M.globals()) {
37    if (!isRSAllocation(GV))
38      continue;
39
40    DEBUG(GV.dump());
41    GlobalAllocs.push_back(&GV);
42  }
43
44  return !GlobalAllocs.empty();
45}
46
47//
48// This pass would enumerate used global rs_allocations (TBD) and
49// lowers calls to accessors of the following type:
50//
51//    rsGetAllocationDimX(g)
52//
53// to
54//
55//    __rsov_rsGetAllocationDimX(some uninque constant identifying g) */
56//
57// Note the __rsov_* variant is used as a marker for another SPIRIT
58// transformations (see GlobalAllocSPIRITPass.cpp) to expand them into
59// SPIR-V instructions that loads the metadata.
60//
61class GlobalAllocPass : public ModulePass {
62public:
63  static char ID;
64  GlobalAllocPass()
65      : ModulePass(ID), Allocs(Context::getInstance().getGlobalAllocs()) {}
66
67  const char *getPassName() const override { return "GlobalAllocPass"; }
68
69  bool runOnModule(Module &M) override {
70    DEBUG(dbgs() << "RS2SPIRVGlobalAllocPass\n");
71    DEBUG(M.dump());
72
73    SmallVector<GlobalVariable *, 8> GlobalAllocs;
74    const bool CollectRes = collectGlobalAllocs(M, GlobalAllocs);
75    if (!CollectRes)
76      return false; // Module not modified.
77
78    SmallVector<RSAllocationCallInfo, 8> Calls;
79    getRSAllocationInfo(M, Allocs);
80    getRSAllocAccesses(Allocs, Calls);
81
82    // Lower the found accessors
83    for (auto &C : Calls) {
84      assert(C.Kind == RSAllocAccessKind::DIMX &&
85             "Unsupported type of accessor call types");
86      solidifyRSAllocAccess(M, C);
87    }
88    // Return true, as the pass modifies module.
89    DEBUG(dbgs() << "RS2SPIRVGlobalAllocPass end\n");
90    return true;
91  }
92
93private:
94  SmallVectorImpl<RSAllocationInfo> &Allocs;
95};
96
97// A simple pass to remove all global allocations forcibly
98class RemoveAllGlobalAllocPass : public ModulePass {
99public:
100  static char ID;
101  RemoveAllGlobalAllocPass() : ModulePass(ID) {}
102  const char *getPassName() const override {
103    return "RemoveAllGlobalAllocPass";
104  }
105
106  bool runOnModule(Module &M) override {
107    DEBUG(dbgs() << "RemoveAllGlobalAllocPass\n");
108    DEBUG(M.dump());
109
110    SmallVector<GlobalVariable *, 8> GlobalAllocs;
111    const bool CollectRes = collectGlobalAllocs(M, GlobalAllocs);
112    if (!CollectRes)
113      return false; // Module not modified.
114    // Remove global allocations
115    for (auto *G : GlobalAllocs) {
116      G->eraseFromParent();
117    }
118    DEBUG(dbgs() << "RemoveAllGlobalAllocPass end\n");
119    DEBUG(M.dump());
120    // Return true, as the pass modifies module.
121    return true;
122  }
123};
124
125} // namespace
126char GlobalAllocPass::ID = 0;
127char RemoveAllGlobalAllocPass::ID = 0;
128
129ModulePass *createRemoveAllGlobalAllocPass() {
130  return new RemoveAllGlobalAllocPass();
131}
132ModulePass *createGlobalAllocPass() { return new GlobalAllocPass(); }
133
134} // namespace rs2spirv
135