blob: 4a0d7cb2c2f3b71e6c62da442e11f224b2ca7034 [file] [log] [blame]
David Neto85082642018-03-24 06:55:20 -07001// 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// Cluster module-scope __constant variables. But only if option
16// ModuleScopeConstantsInUniformBuffer is true.
17
18#include <cassert>
19
David Neto118188e2018-08-24 11:27:54 -040020#include "llvm/ADT/SmallVector.h"
21#include "llvm/ADT/UniqueVector.h"
22#include "llvm/IR/Constants.h"
23#include "llvm/IR/DerivedTypes.h"
24#include "llvm/IR/Function.h"
25#include "llvm/IR/GlobalVariable.h"
David Neto118188e2018-08-24 11:27:54 -040026#include "llvm/IR/IRBuilder.h"
Diego Novillo3cc8d7a2019-04-10 13:30:34 -040027#include "llvm/IR/Instructions.h"
David Neto118188e2018-08-24 11:27:54 -040028#include "llvm/IR/Module.h"
29#include "llvm/Pass.h"
30#include "llvm/Support/raw_ostream.h"
David Neto85082642018-03-24 06:55:20 -070031
32#include "clspv/AddressSpace.h"
33#include "clspv/Option.h"
34
35#include "ArgKind.h"
Diego Novilloa4c44fa2019-04-11 10:56:15 -040036#include "Passes.h"
David Neto85082642018-03-24 06:55:20 -070037
38using namespace llvm;
39
40#define DEBUG_TYPE "clusterconstants"
41
42namespace {
43struct ClusterModuleScopeConstantVars : public ModulePass {
44 static char ID;
45 ClusterModuleScopeConstantVars() : ModulePass(ID) {}
46
47 bool runOnModule(Module &M) override;
48};
49
50} // namespace
51
52char ClusterModuleScopeConstantVars::ID = 0;
Diego Novilloa4c44fa2019-04-11 10:56:15 -040053INITIALIZE_PASS(ClusterModuleScopeConstantVars,
54 "ClusterModuleScopeConstantVars",
55 "Cluster module-scope __constant variables", false, false)
David Neto85082642018-03-24 06:55:20 -070056
57namespace clspv {
58llvm::ModulePass *createClusterModuleScopeConstantVars() {
59 return new ClusterModuleScopeConstantVars();
60}
61} // namespace clspv
62
63bool ClusterModuleScopeConstantVars::runOnModule(Module &M) {
64 bool Changed = false;
65 LLVMContext &Context = M.getContext();
66
67 SmallVector<GlobalVariable *, 8> global_constants;
68 UniqueVector<Constant *> initializers;
69 SmallVector<GlobalVariable *, 8> dead_global_constants;
70 for (GlobalVariable &GV : M.globals()) {
71 if (GV.hasInitializer() && GV.getType()->getPointerAddressSpace() ==
72 clspv::AddressSpace::Constant) {
73 // Only keep live __constant variables.
74 if (GV.use_empty()) {
75 dead_global_constants.push_back(&GV);
76 } else {
77 global_constants.push_back(&GV);
78 initializers.insert(GV.getInitializer());
79 }
80 }
81 }
82
83 for (GlobalVariable *GV : dead_global_constants) {
84 Changed = true;
85 GV->eraseFromParent();
86 }
87
88 if (global_constants.size() > 1 ||
89 (global_constants.size() == 1 &&
90 !global_constants[0]->getType()->isStructTy())) {
91
92 Changed = true;
93
94 // Make the struct type.
95 SmallVector<Type *, 8> types;
96 types.reserve(initializers.size());
97 for (Value *init : initializers) {
98 Type *ty = init->getType();
99 types.push_back(ty);
100 }
101 StructType *type = StructType::get(Context, types);
102
103 // Make the global variable.
104 SmallVector<Constant *, 8> initializers_as_vec(initializers.begin(),
105 initializers.end());
106 Constant *clustered_initializer =
107 ConstantStruct::get(type, initializers_as_vec);
108 GlobalVariable *clustered_gv = new GlobalVariable(
109 M, type, true, GlobalValue::InternalLinkage, clustered_initializer,
110 "clspv.clustered_constants", nullptr,
111 GlobalValue::ThreadLocalMode::NotThreadLocal,
112 clspv::AddressSpace::Constant);
113 assert(clustered_gv);
114
115 // Replace uses of the other globals with references to the members of the
116 // clustered constant.
117 IRBuilder<> Builder(Context);
118 Value *zero = Builder.getInt32(0);
119 for (GlobalVariable *GV : global_constants) {
120 SmallVector<User *, 8> users(GV->users());
121 for (User *user : users) {
122 if (GV == user) {
123 // This is the original global variable declaration. Skip it.
124 } else if (auto *inst = dyn_cast<Instruction>(user)) {
125 unsigned index = initializers.idFor(GV->getInitializer()) - 1;
126 Instruction *gep = GetElementPtrInst::CreateInBounds(
127 clustered_gv, {zero, Builder.getInt32(index)}, "", inst);
128 user->replaceUsesOfWith(GV, gep);
129 } else {
130 errs() << "Don't know how to handle updating user of __constant: "
131 << *user << "\n";
132 llvm_unreachable("Unhandled case replacing a user of __constant");
133 }
134 }
135 }
136
137 // Remove the old constants.
138 for (GlobalVariable *GV : global_constants) {
139 GV->eraseFromParent();
140 }
141 }
142
143 return Changed;
144}