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