blob: d935267e187761efdc7a38c3fb4476ede4e7a4b9 [file] [log] [blame]
David Neto6373d822017-10-12 19:09:53 -04001// Copyright 2017 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 <string>
16
David Neto118188e2018-08-24 11:27:54 -040017#include "llvm/ADT/DenseMap.h"
18#include "llvm/IR/Attributes.h"
19#include "llvm/IR/DerivedTypes.h"
20#include "llvm/IR/Function.h"
21#include "llvm/IR/Instructions.h"
22#include "llvm/IR/Module.h"
23#include "llvm/Pass.h"
24#include "llvm/Support/raw_ostream.h"
David Neto6373d822017-10-12 19:09:53 -040025
David Neto118188e2018-08-24 11:27:54 -040026#include "clspv/AddressSpace.h"
David Neto6373d822017-10-12 19:09:53 -040027
Diego Novilloa4c44fa2019-04-11 10:56:15 -040028#include "Passes.h"
29
David Neto6373d822017-10-12 19:09:53 -040030using namespace llvm;
31using std::string;
32
33#define DEBUG_TYPE "hideconstantloads"
34
David Neto6373d822017-10-12 19:09:53 -040035namespace {
36
Diego Novillo3cc8d7a2019-04-10 13:30:34 -040037const char *kWrapFunctionPrefix = "clspv.wrap_constant_load.";
David Neto6373d822017-10-12 19:09:53 -040038
39class HideConstantLoadsPass : public ModulePass {
Diego Novillo3cc8d7a2019-04-10 13:30:34 -040040public:
David Neto6373d822017-10-12 19:09:53 -040041 static char ID;
42 HideConstantLoadsPass() : ModulePass(ID) {}
43
44 bool runOnModule(Module &M) override;
45
Diego Novillo3cc8d7a2019-04-10 13:30:34 -040046private:
47 // Return the name for the wrap function for the given type.
48 string &WrapFunctionNameForType(Type *type) {
49 auto where = function_for_type_.find(type);
50 if (where == function_for_type_.end()) {
51 // Insert it.
52 auto &result = function_for_type_[type] =
53 string(kWrapFunctionPrefix) +
54 std::to_string(function_for_type_.size());
55 return result;
56 } else {
57 return where->second;
58 }
59 }
David Neto6373d822017-10-12 19:09:53 -040060
Diego Novillo3cc8d7a2019-04-10 13:30:34 -040061 // Maps a loaded type to the name of the wrap function for that type.
62 DenseMap<Type *, string> function_for_type_;
David Neto6373d822017-10-12 19:09:53 -040063};
64} // namespace
65
66char HideConstantLoadsPass::ID = 0;
Diego Novilloa4c44fa2019-04-11 10:56:15 -040067INITIALIZE_PASS(HideConstantLoadsPass, "HideConstantLoads",
68 "Hide loads from __constant memory", false, false)
David Neto6373d822017-10-12 19:09:53 -040069
70namespace clspv {
71llvm::ModulePass *createHideConstantLoadsPass() {
72 return new HideConstantLoadsPass();
73}
74} // namespace clspv
75
David Neto6373d822017-10-12 19:09:53 -040076bool HideConstantLoadsPass::runOnModule(Module &M) {
77 bool Changed = false;
78
79 SmallVector<LoadInst *, 16> WorkList;
80 for (Function &F : M) {
81 for (BasicBlock &BB : F) {
82 for (Instruction &I : BB) {
83 if (LoadInst *load = dyn_cast<LoadInst>(&I)) {
84 if (clspv::AddressSpace::Constant == load->getPointerAddressSpace()) {
85 WorkList.push_back(load);
86 }
87 }
88 }
89 }
90 }
91
92 if (WorkList.size() == 0) {
93 return Changed;
94 }
95
96 for (LoadInst *load : WorkList) {
97 Changed = true;
98
99 auto loadedTy = load->getType();
100
101 // The wrap function conceptually maps the loaded value to itself.
Diego Novillo3cc8d7a2019-04-10 13:30:34 -0400102 const string &fn_name = WrapFunctionNameForType(loadedTy);
103 Function *fn = M.getFunction(fn_name);
David Neto6373d822017-10-12 19:09:53 -0400104 if (!fn) {
105 // Make the function.
Diego Novillo3cc8d7a2019-04-10 13:30:34 -0400106 FunctionType *fnTy = FunctionType::get(loadedTy, {loadedTy}, false);
David Neto6373d822017-10-12 19:09:53 -0400107 auto fn_constant = M.getOrInsertFunction(fn_name, fnTy);
alan-bakerbccf62c2019-03-29 10:32:41 -0400108 fn = cast<Function>(fn_constant.getCallee());
David Neto6373d822017-10-12 19:09:53 -0400109 fn->addFnAttr(Attribute::ReadOnly);
David Neto6373d822017-10-12 19:09:53 -0400110 }
111
112 // Wrap the load
113 auto call = CallInst::Create(fn, {load});
114 call->insertAfter(load);
115
116 // Replace other uses of the load with the result of the wrap call.
117 {
118 SmallVector<User *, 16> ToReplaceIn;
119 for (auto &use : load->uses()) {
120 User *user = use.getUser();
121 ToReplaceIn.push_back(user);
122 }
123 for (auto *user : ToReplaceIn) {
124 if (dyn_cast<CallInst>(user) != call) {
125 user->replaceUsesOfWith(load, call);
126 }
127 }
128 }
129 }
130
131 return Changed;
132}
133
134namespace {
135class UnhideConstantLoadsPass : public ModulePass {
Diego Novillo3cc8d7a2019-04-10 13:30:34 -0400136public:
David Neto6373d822017-10-12 19:09:53 -0400137 static char ID;
138 UnhideConstantLoadsPass() : ModulePass(ID) {}
139
140 bool runOnModule(Module &M) override;
141
Diego Novillo3cc8d7a2019-04-10 13:30:34 -0400142private:
143 // Maps a loaded type to the name of the wrap function for that type.
144 DenseMap<Type *, string> function_for_type_;
David Neto6373d822017-10-12 19:09:53 -0400145};
146
147} // namespace
148
149char UnhideConstantLoadsPass::ID = 0;
Diego Novilloa4c44fa2019-04-11 10:56:15 -0400150INITIALIZE_PASS(UnhideConstantLoadsPass, "UnhideConstantLoads",
151 "Unhide loads from __constant memory", false, false)
David Neto6373d822017-10-12 19:09:53 -0400152
153namespace clspv {
154llvm::ModulePass *createUnhideConstantLoadsPass() {
155 return new UnhideConstantLoadsPass();
156}
157} // namespace clspv
158
159bool UnhideConstantLoadsPass::runOnModule(Module &M) {
160 bool Changed = false;
161
162 SmallVector<Function *, 16> WorkList;
Diego Novillo3cc8d7a2019-04-10 13:30:34 -0400163 for (auto &F : M.getFunctionList()) {
David Neto6373d822017-10-12 19:09:53 -0400164 if (F.getName().startswith(kWrapFunctionPrefix)) {
165 WorkList.push_back(&F);
166 }
167 }
168
169 if (WorkList.size() == 0)
170 return Changed;
171
172 SmallVector<CallInst *, 16> RemoveList;
Diego Novillo3cc8d7a2019-04-10 13:30:34 -0400173 for (auto *F : WorkList) {
174 for (auto &use : F->uses()) {
175 if (auto *call = dyn_cast<CallInst>(use.getUser())) {
David Neto6373d822017-10-12 19:09:53 -0400176 assert(call->getNumArgOperands() == 1);
Diego Novillo3cc8d7a2019-04-10 13:30:34 -0400177 auto *load = call->getArgOperand(0);
David Neto6373d822017-10-12 19:09:53 -0400178 call->replaceAllUsesWith(load);
179 RemoveList.push_back(call);
180 }
181 }
182 }
Diego Novillo3cc8d7a2019-04-10 13:30:34 -0400183 for (auto *call : RemoveList) {
David Neto6373d822017-10-12 19:09:53 -0400184 call->eraseFromParent();
185 }
Diego Novillo3cc8d7a2019-04-10 13:30:34 -0400186 for (auto *F : WorkList) {
David Neto6373d822017-10-12 19:09:53 -0400187 F->eraseFromParent();
188 }
189
190 return Changed;
191}