blob: 2ebccb302c0c84c60abb3375543e5d70cd123a9e [file] [log] [blame]
David Neto22f144c2017-06-12 14:26:21 -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
David Neto862b7d82018-06-14 18:48:37 -040015#include "llvm/IR/IRBuilder.h"
16#include "llvm/IR/Instructions.h"
17#include "llvm/IR/Module.h"
18#include "llvm/Pass.h"
19#include "llvm/Support/raw_ostream.h"
David Neto22f144c2017-06-12 14:26:21 -040020
Diego Novilloa4c44fa2019-04-11 10:56:15 -040021#include "Passes.h"
22
David Neto22f144c2017-06-12 14:26:21 -040023using namespace llvm;
24
25#define DEBUG_TYPE "SimplifyPointerBitcast"
26
27namespace {
28struct SimplifyPointerBitcastPass : public ModulePass {
29 static char ID;
30 SimplifyPointerBitcastPass() : ModulePass(ID) {}
31
32 bool runOnModule(Module &M) override;
33
David Neto973e6a82017-05-30 13:48:18 -040034 bool runOnTrivialBitcast(Module &M) const;
David Neto22f144c2017-06-12 14:26:21 -040035 bool runOnBitcastFromBitcast(Module &M) const;
36 bool runOnBitcastFromGEP(Module &M) const;
37 bool runOnGEPFromGEP(Module &M) const;
38};
Diego Novillo3cc8d7a2019-04-10 13:30:34 -040039} // namespace
David Neto22f144c2017-06-12 14:26:21 -040040
41char SimplifyPointerBitcastPass::ID = 0;
Diego Novilloa4c44fa2019-04-11 10:56:15 -040042INITIALIZE_PASS(SimplifyPointerBitcastPass, "SimplifyPointerBitcast",
43 "Simplify Pointer Bitcast Pass", false, false)
David Neto22f144c2017-06-12 14:26:21 -040044
45namespace clspv {
46llvm::ModulePass *createSimplifyPointerBitcastPass() {
47 return new SimplifyPointerBitcastPass();
48}
Diego Novillo3cc8d7a2019-04-10 13:30:34 -040049} // namespace clspv
David Neto22f144c2017-06-12 14:26:21 -040050
51bool SimplifyPointerBitcastPass::runOnModule(Module &M) {
52 bool Changed = false;
53
54 // Loop through our individual simplification passes until they stop changing
55 // things.
56 for (bool localChanged = true; localChanged; Changed |= localChanged) {
57 localChanged = false;
58
David Neto973e6a82017-05-30 13:48:18 -040059 localChanged |= runOnTrivialBitcast(M);
David Neto22f144c2017-06-12 14:26:21 -040060 localChanged |= runOnBitcastFromGEP(M);
61 localChanged |= runOnBitcastFromBitcast(M);
62 localChanged |= runOnGEPFromGEP(M);
63 }
64
65 return Changed;
66}
67
David Neto973e6a82017-05-30 13:48:18 -040068bool SimplifyPointerBitcastPass::runOnTrivialBitcast(Module &M) const {
69 // Remove things like:
70 // bitcast i32 addrspace(1)* %ptr to i32 addrspace(1)*
71
72 SmallVector<BitCastInst *, 16> WorkList;
73 for (Function &F : M) {
74 for (BasicBlock &BB : F) {
75 for (Instruction &I : BB) {
76 // If we have a bitcast instruction...
77 if (auto Bitcast = dyn_cast<BitCastInst>(&I)) {
78 // ... whose source type is the same as the destination type.
79 auto Source = Bitcast->getOperand(0);
80 if (Source->getType() == Bitcast->getType()) {
81 // ... record the bitcast as something we need to process.
82 WorkList.push_back(Bitcast);
83 }
84 }
85 }
86 }
87 }
88
89 const bool Changed = !WorkList.empty();
90
91 for (auto Bitcast : WorkList) {
92 auto Source = Bitcast->getOperand(0);
93 Bitcast->replaceAllUsesWith(Source);
94
95 // Remove the bitcast as it has no users now.
96 Bitcast->eraseFromParent();
97
98 // Check if the source value is an instruction and had no other users...
99 if (auto SourceInst = dyn_cast<Instruction>(Source)) {
100 if (0 == SourceInst->getNumUses()) {
101 // ... and remove it if we were its only user.
102 SourceInst->eraseFromParent();
103 }
104 }
105 }
106
107 return Changed;
108}
109
David Neto22f144c2017-06-12 14:26:21 -0400110bool SimplifyPointerBitcastPass::runOnBitcastFromGEP(Module &M) const {
111 SmallVector<BitCastInst *, 16> WorkList;
112 for (Function &F : M) {
113 for (BasicBlock &BB : F) {
114 for (Instruction &I : BB) {
115 // If we have a bitcast instruction...
116 if (auto Bitcast = dyn_cast<BitCastInst>(&I)) {
117 // ... whose source is a GEP instruction...
118 if (auto GEP = dyn_cast<GetElementPtrInst>(Bitcast->getOperand(0))) {
119 // ... where the GEP is retrieving an element of the same type...
120 if (GEP->getSourceElementType() == GEP->getResultElementType()) {
121 auto GEPTy = GEP->getResultElementType();
122 auto BitcastTy = Bitcast->getType()->getPointerElementType();
123 // ... and the types have a known compile time size...
124 if ((0 != GEPTy->getPrimitiveSizeInBits()) &&
125 (0 != BitcastTy->getPrimitiveSizeInBits())) {
126 // ... record the bitcast as something we need to process.
127 WorkList.push_back(Bitcast);
128 }
129 }
130 }
131 }
132 }
133 }
134 }
135
136 const bool Changed = !WorkList.empty();
137
138 for (auto Bitcast : WorkList) {
139 auto BitcastTy = Bitcast->getType();
140 auto BitcastElementTy = BitcastTy->getPointerElementType();
141
142 auto GEP = cast<GetElementPtrInst>(Bitcast->getOperand(0));
143
144 auto SrcTySize = GEP->getResultElementType()->getPrimitiveSizeInBits();
145 auto DstTySize = BitcastElementTy->getPrimitiveSizeInBits();
146
147 SmallVector<Value *, 4> GEPArgs(GEP->idx_begin(), GEP->idx_end());
148
149 // If the source type is smaller than the destination type...
150 if (SrcTySize < DstTySize) {
151 // ... we need to divide the last index of the GEP by the size difference.
152 auto LastIndex = GEPArgs.back();
153 GEPArgs.back() = BinaryOperator::Create(
154 Instruction::SDiv, LastIndex,
155 ConstantInt::get(LastIndex->getType(), DstTySize / SrcTySize), "",
156 Bitcast);
157 } else if (SrcTySize > DstTySize) {
158 // ... we need to multiply the last index of the GEP by the size
159 // difference.
160 auto LastIndex = GEPArgs.back();
161 GEPArgs.back() = BinaryOperator::Create(
162 Instruction::Mul, LastIndex,
163 ConstantInt::get(LastIndex->getType(), SrcTySize / DstTySize), "",
164 Bitcast);
165 } else {
166 // ... the arguments are the same size, nothing to do!
167 }
168
169 // Create a new bitcast from the GEP argument to the bitcast type.
170 auto NewBitcast = CastInst::CreatePointerCast(GEP->getPointerOperand(),
171 BitcastTy, "", Bitcast);
172
173 // Create a new GEP from the (maybe modified) GEPArgs.
174 auto NewGEP = GetElementPtrInst::Create(BitcastElementTy, NewBitcast,
175 GEPArgs, "", Bitcast);
176
177 // And replace the original bitcast with our replacement GEP.
178 Bitcast->replaceAllUsesWith(NewGEP);
179
180 // Remove the bitcast as it has no users now.
181 Bitcast->eraseFromParent();
182
183 // Check if the old GEP had no other users...
184 if (0 == GEP->getNumUses()) {
185 // ... and remove it if we were its only user.
186 GEP->eraseFromParent();
187 }
188 }
189
190 return Changed;
191}
192
193bool SimplifyPointerBitcastPass::runOnBitcastFromBitcast(Module &M) const {
194 SmallVector<BitCastInst *, 16> WorkList;
195 for (Function &F : M) {
196 for (BasicBlock &BB : F) {
197 for (Instruction &I : BB) {
198 // If we have a bitcast instruction...
199 if (auto Bitcast = dyn_cast<BitCastInst>(&I)) {
200 // ... whose source is a bitcast instruction...
201 if (isa<BitCastInst>(Bitcast->getOperand(0))) {
202 // ... record the bitcast as something we need to process.
203 WorkList.push_back(Bitcast);
204 }
205 }
206 }
207 }
208 }
209
210 const bool Changed = !WorkList.empty();
211
212 for (auto Bitcast : WorkList) {
213 auto OtherBitcast = cast<BitCastInst>(Bitcast->getOperand(0));
214
David Neto973e6a82017-05-30 13:48:18 -0400215 if (OtherBitcast->getType() == Bitcast->getType()) {
216 Bitcast->replaceAllUsesWith(OtherBitcast);
217 } else {
218 // Create a new bitcast from the other bitcasts argument to our type.
Marco Antognini5cdbce32020-09-01 14:26:06 +0100219 auto NewBitcast =
220 CastInst::Create(Instruction::BitCast, OtherBitcast->getOperand(0),
221 Bitcast->getType(), "", Bitcast);
David Neto22f144c2017-06-12 14:26:21 -0400222
David Neto973e6a82017-05-30 13:48:18 -0400223 // And replace the original bitcast with our replacement bitcast.
224 Bitcast->replaceAllUsesWith(NewBitcast);
225 }
David Neto22f144c2017-06-12 14:26:21 -0400226
227 // Remove the bitcast as it has no users now.
228 Bitcast->eraseFromParent();
229
230 // Check if the other bitcast had no other users...
231 if (0 == OtherBitcast->getNumUses()) {
232 // ... and remove it if we were its only user.
233 OtherBitcast->eraseFromParent();
234 }
235 }
236
237 return Changed;
238}
239
240bool SimplifyPointerBitcastPass::runOnGEPFromGEP(Module &M) const {
241 SmallVector<GetElementPtrInst *, 16> WorkList;
242 for (Function &F : M) {
243 for (BasicBlock &BB : F) {
244 for (Instruction &I : BB) {
245 // If we have a GEP instruction...
246 if (auto GEP = dyn_cast<GetElementPtrInst>(&I)) {
247 // ... whose operand is also a GEP instruction...
248 if (isa<GetElementPtrInst>(GEP->getPointerOperand())) {
249 // ... record the GEP as something we need to process.
250 WorkList.push_back(GEP);
251 }
252 }
253 }
254 }
255 }
256
257 const bool Changed = !WorkList.empty();
258
259 for (GetElementPtrInst *GEP : WorkList) {
260 IRBuilder<> Builder(GEP);
261
262 auto OtherGEP = cast<GetElementPtrInst>(GEP->getPointerOperand());
263
264 SmallVector<Value *, 8> Idxs;
265
266 Value *SrcLastIdxOp = OtherGEP->getOperand(OtherGEP->getNumOperands() - 1);
David Neto862b7d82018-06-14 18:48:37 -0400267
David Neto22f144c2017-06-12 14:26:21 -0400268 Value *GEPIdxOp = GEP->getOperand(1);
David Neto862b7d82018-06-14 18:48:37 -0400269 Value *MergedIdx = GEPIdxOp;
270
271 // Add the indices together, if the last one from before is not zero.
272 bool last_idx_is_zero = false;
273 if (auto *constant = dyn_cast<ConstantInt>(SrcLastIdxOp)) {
274 last_idx_is_zero = constant->isZero();
275 }
276 if (!last_idx_is_zero) {
277 MergedIdx = Builder.CreateAdd(SrcLastIdxOp, GEPIdxOp);
278 }
David Neto22f144c2017-06-12 14:26:21 -0400279
280 Idxs.append(OtherGEP->op_begin() + 1, OtherGEP->op_end() - 1);
281 Idxs.push_back(MergedIdx);
282 Idxs.append(GEP->op_begin() + 2, GEP->op_end());
283
284 Value *NewGEP = nullptr;
David Neto862b7d82018-06-14 18:48:37 -0400285 // Create the new GEP. If we used the Builder it will do some folding
286 // that we don't want. In particular, if the first GEP is to an LLVM
287 // constant then the combined GEP will become a ConstantExpr and it
288 // will hide the pointer from subsequent passes. So bypass the Builder
289 // and create the GEP instruction directly.
David Neto22f144c2017-06-12 14:26:21 -0400290 if (GEP->isInBounds() && OtherGEP->isInBounds()) {
David Neto862b7d82018-06-14 18:48:37 -0400291 NewGEP = GetElementPtrInst::CreateInBounds(
James Price06f91142021-07-15 20:03:29 -0400292 OtherGEP->getSourceElementType(), OtherGEP->getPointerOperand(), Idxs,
293 "", GEP);
David Neto22f144c2017-06-12 14:26:21 -0400294 } else {
James Price06f91142021-07-15 20:03:29 -0400295 NewGEP = GetElementPtrInst::Create(OtherGEP->getSourceElementType(),
296 OtherGEP->getPointerOperand(), Idxs,
297 "", GEP);
David Neto22f144c2017-06-12 14:26:21 -0400298 }
299
300 // And replace the original GEP with our replacement GEP.
301 GEP->replaceAllUsesWith(NewGEP);
302
303 // Remove the GEP as it has no users now.
304 GEP->eraseFromParent();
305
306 // Check if the other GEP had no other users...
307 if (0 == OtherGEP->getNumUses()) {
308 // ... and remove it if we were its only user.
309 OtherGEP->eraseFromParent();
310 }
311 }
312
313 return Changed;
314}