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