blob: 5b93c14e39ef8f1173f52a24b7365820eafcae97 [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 Netoe345e0e2018-06-15 11:38:32 -040015#include "llvm/IR/Constants.h"
16#include "llvm/IR/IRBuilder.h"
17#include "llvm/IR/Instructions.h"
alan-bakerbccf62c2019-03-29 10:32:41 -040018#include "llvm/IR/IntrinsicInst.h"
David Netoe345e0e2018-06-15 11:38:32 -040019#include "llvm/IR/Module.h"
20#include "llvm/Pass.h"
21#include "llvm/Support/raw_ostream.h"
22#include "llvm/Transforms/Utils/Cloning.h"
David Neto22f144c2017-06-12 14:26:21 -040023
alan-bakere0902602020-03-23 08:43:40 -040024#include "spirv/unified1/spirv.hpp"
David Neto22f144c2017-06-12 14:26:21 -040025
SJW61531372020-06-09 07:31:08 -050026#include "Constants.h"
Diego Novilloa4c44fa2019-04-11 10:56:15 -040027#include "Passes.h"
28
David Neto22f144c2017-06-12 14:26:21 -040029using namespace llvm;
30
31#define DEBUG_TYPE "ReplaceLLVMIntrinsics"
32
33namespace {
34struct ReplaceLLVMIntrinsicsPass final : public ModulePass {
35 static char ID;
36 ReplaceLLVMIntrinsicsPass() : ModulePass(ID) {}
37
38 bool runOnModule(Module &M) override;
39 bool replaceMemset(Module &M);
40 bool replaceMemcpy(Module &M);
David Netoe345e0e2018-06-15 11:38:32 -040041 bool removeLifetimeDeclarations(Module &M);
David Neto22f144c2017-06-12 14:26:21 -040042};
Diego Novillo3cc8d7a2019-04-10 13:30:34 -040043} // namespace
David Neto22f144c2017-06-12 14:26:21 -040044
45char ReplaceLLVMIntrinsicsPass::ID = 0;
Diego Novilloa4c44fa2019-04-11 10:56:15 -040046INITIALIZE_PASS(ReplaceLLVMIntrinsicsPass, "ReplaceLLVMIntrinsics",
47 "Replace LLVM intrinsics Pass", false, false)
David Neto22f144c2017-06-12 14:26:21 -040048
49namespace clspv {
50ModulePass *createReplaceLLVMIntrinsicsPass() {
51 return new ReplaceLLVMIntrinsicsPass();
52}
Diego Novillo3cc8d7a2019-04-10 13:30:34 -040053} // namespace clspv
David Neto22f144c2017-06-12 14:26:21 -040054
55bool ReplaceLLVMIntrinsicsPass::runOnModule(Module &M) {
56 bool Changed = false;
57
David Netoe345e0e2018-06-15 11:38:32 -040058 // Remove lifetime annotations first. They coulud be using memset
59 // and memcpy calls.
60 Changed |= removeLifetimeDeclarations(M);
David Neto22f144c2017-06-12 14:26:21 -040061 Changed |= replaceMemset(M);
62 Changed |= replaceMemcpy(M);
63
64 return Changed;
65}
66
67bool ReplaceLLVMIntrinsicsPass::replaceMemset(Module &M) {
68 bool Changed = false;
David Netod3f59382017-10-18 18:30:30 -040069 auto Layout = M.getDataLayout();
David Neto22f144c2017-06-12 14:26:21 -040070
71 for (auto &F : M) {
72 if (F.getName().startswith("llvm.memset")) {
73 SmallVector<CallInst *, 8> CallsToReplace;
74
75 for (auto U : F.users()) {
76 if (auto CI = dyn_cast<CallInst>(U)) {
77 auto Initializer = dyn_cast<ConstantInt>(CI->getArgOperand(1));
78
79 // We only handle cases where the initializer is a constant int that
80 // is 0.
81 if (!Initializer || (0 != Initializer->getZExtValue())) {
82 Initializer->print(errs());
83 llvm_unreachable("Unhandled llvm.memset.* instruction that had a "
84 "non-0 initializer!");
85 }
86
87 CallsToReplace.push_back(CI);
88 }
89 }
90
91 for (auto CI : CallsToReplace) {
92 auto NewArg = CI->getArgOperand(0);
Kévin Petit70944912019-04-17 23:22:28 +010093 auto Bitcast = dyn_cast<BitCastInst>(NewArg);
94 if (Bitcast != nullptr) {
David Neto22f144c2017-06-12 14:26:21 -040095 NewArg = Bitcast->getOperand(0);
96 }
97
David Netod3f59382017-10-18 18:30:30 -040098 auto NumBytes = cast<ConstantInt>(CI->getArgOperand(2))->getZExtValue();
David Neto22f144c2017-06-12 14:26:21 -040099 auto Ty = NewArg->getType();
100 auto PointeeTy = Ty->getPointerElementType();
David Neto22f144c2017-06-12 14:26:21 -0400101 auto Zero = Constant::getNullValue(PointeeTy);
102
David Netod3f59382017-10-18 18:30:30 -0400103 const auto num_stores = NumBytes / Layout.getTypeAllocSize(PointeeTy);
104 assert((NumBytes == num_stores * Layout.getTypeAllocSize(PointeeTy)) &&
105 "Null memset can't be divided evenly across multiple stores.");
106 assert((num_stores & 0xFFFFFFFF) == num_stores);
David Neto22f144c2017-06-12 14:26:21 -0400107
David Netod3f59382017-10-18 18:30:30 -0400108 // Generate the first store.
Kévin Petit58c445c2019-06-18 18:09:46 +0100109 new StoreInst(Zero, NewArg, CI);
David Netod3f59382017-10-18 18:30:30 -0400110
111 // Generate subsequent stores, but only if needed.
112 if (num_stores) {
113 auto I32Ty = Type::getInt32Ty(M.getContext());
114 auto One = ConstantInt::get(I32Ty, 1);
115 auto Ptr = NewArg;
116 for (uint32_t i = 1; i < num_stores; i++) {
117 Ptr = GetElementPtrInst::Create(PointeeTy, Ptr, {One}, "", CI);
Kévin Petit58c445c2019-06-18 18:09:46 +0100118 new StoreInst(Zero, Ptr, CI);
David Netod3f59382017-10-18 18:30:30 -0400119 }
120 }
121
David Neto22f144c2017-06-12 14:26:21 -0400122 CI->eraseFromParent();
123
Kévin Petit70944912019-04-17 23:22:28 +0100124 if (Bitcast != nullptr) {
David Neto22f144c2017-06-12 14:26:21 -0400125 Bitcast->eraseFromParent();
126 }
127 }
128 }
129 }
130
131 return Changed;
132}
133
134bool ReplaceLLVMIntrinsicsPass::replaceMemcpy(Module &M) {
135 bool Changed = false;
David Netob84ba342017-06-19 17:55:37 -0400136 auto Layout = M.getDataLayout();
137
138 // Unpack source and destination types until we find a matching
139 // element type. Count the number of levels we unpack for the
140 // source and destination types. So far this only works for
141 // array types, but could be generalized to other regular types
142 // like vectors.
Alan Baker7dea8842018-10-22 10:15:41 -0400143 auto match_types = [&Layout](CallInst &CI, uint64_t Size, Type **DstElemTy,
144 Type **SrcElemTy, unsigned *NumDstUnpackings,
David Netob84ba342017-06-19 17:55:37 -0400145 unsigned *NumSrcUnpackings) {
Alan Baker7dea8842018-10-22 10:15:41 -0400146 auto descend_type = [](Type *InType) {
147 Type *OutType = InType;
148 if (OutType->isStructTy()) {
149 OutType = OutType->getStructElementType(0);
150 } else if (OutType->isArrayTy()) {
151 OutType = OutType->getArrayElementType();
James Pricecf53df42020-04-20 14:41:24 -0400152 } else if (auto vec_type = dyn_cast<VectorType>(OutType)) {
153 OutType = vec_type->getElementType();
Alan Baker7dea8842018-10-22 10:15:41 -0400154 } else {
155 assert(false && "Don't know how to descend into type");
156 }
157
158 return OutType;
159 };
160
David Netob84ba342017-06-19 17:55:37 -0400161 while (*SrcElemTy != *DstElemTy) {
162 auto SrcElemSize = Layout.getTypeSizeInBits(*SrcElemTy);
163 auto DstElemSize = Layout.getTypeSizeInBits(*DstElemTy);
164 if (SrcElemSize >= DstElemSize) {
Alan Baker7dea8842018-10-22 10:15:41 -0400165 *SrcElemTy = descend_type(*SrcElemTy);
David Netob84ba342017-06-19 17:55:37 -0400166 (*NumSrcUnpackings)++;
167 } else if (DstElemSize >= SrcElemSize) {
Alan Baker7dea8842018-10-22 10:15:41 -0400168 *DstElemTy = descend_type(*DstElemTy);
David Netob84ba342017-06-19 17:55:37 -0400169 (*NumDstUnpackings)++;
170 } else {
171 errs() << "Don't know how to unpack types for memcpy: " << CI
172 << "\ngot to: " << **DstElemTy << " vs " << **SrcElemTy << "\n";
173 assert(false && "Don't know how to unpack these types");
174 }
175 }
Alan Baker7dea8842018-10-22 10:15:41 -0400176
177 auto DstElemSize = Layout.getTypeSizeInBits(*DstElemTy) / 8;
178 while (Size < DstElemSize) {
179 *DstElemTy = descend_type(*DstElemTy);
180 *SrcElemTy = descend_type(*SrcElemTy);
181 (*NumDstUnpackings)++;
182 (*NumSrcUnpackings)++;
183 DstElemSize = Layout.getTypeSizeInBits(*DstElemTy) / 8;
184 }
David Netob84ba342017-06-19 17:55:37 -0400185 };
David Neto22f144c2017-06-12 14:26:21 -0400186
187 for (auto &F : M) {
188 if (F.getName().startswith("llvm.memcpy")) {
David Netob84ba342017-06-19 17:55:37 -0400189 SmallPtrSet<Instruction *, 8> BitCastsToForget;
190 SmallVector<CallInst *, 8> CallsToReplaceWithSpirvCopyMemory;
David Neto22f144c2017-06-12 14:26:21 -0400191
192 for (auto U : F.users()) {
193 if (auto CI = dyn_cast<CallInst>(U)) {
alan-bakered80f572019-02-11 17:28:26 -0500194 assert(isa<BitCastOperator>(CI->getArgOperand(0)));
Diego Novillo3cc8d7a2019-04-10 13:30:34 -0400195 auto Dst =
196 dyn_cast<BitCastOperator>(CI->getArgOperand(0))->getOperand(0);
David Neto22f144c2017-06-12 14:26:21 -0400197
alan-bakered80f572019-02-11 17:28:26 -0500198 assert(isa<BitCastOperator>(CI->getArgOperand(1)));
Diego Novillo3cc8d7a2019-04-10 13:30:34 -0400199 auto Src =
200 dyn_cast<BitCastOperator>(CI->getArgOperand(1))->getOperand(0);
David Neto22f144c2017-06-12 14:26:21 -0400201
202 // The original type of Dst we get from the argument to the bitcast
203 // instruction.
204 auto DstTy = Dst->getType();
205 assert(DstTy->isPointerTy());
206
207 // The original type of Src we get from the argument to the bitcast
208 // instruction.
209 auto SrcTy = Src->getType();
210 assert(SrcTy->isPointerTy());
211
David Neto22f144c2017-06-12 14:26:21 -0400212 // Check that the size is a constant integer.
213 assert(isa<ConstantInt>(CI->getArgOperand(2)));
214 auto Size =
215 dyn_cast<ConstantInt>(CI->getArgOperand(2))->getZExtValue();
216
Alan Baker7dea8842018-10-22 10:15:41 -0400217 auto DstElemTy = DstTy->getPointerElementType();
218 auto SrcElemTy = SrcTy->getPointerElementType();
219 unsigned NumDstUnpackings = 0;
220 unsigned NumSrcUnpackings = 0;
221 match_types(*CI, Size, &DstElemTy, &SrcElemTy, &NumDstUnpackings,
222 &NumSrcUnpackings);
223
224 // Check that the pointee types match.
225 assert(DstElemTy == SrcElemTy);
226
David Netob84ba342017-06-19 17:55:37 -0400227 auto DstElemSize = Layout.getTypeSizeInBits(DstElemTy) / 8;
alan-baker4a757f62020-04-22 08:17:49 -0400228 (void)DstElemSize;
David Neto22f144c2017-06-12 14:26:21 -0400229
David Netob84ba342017-06-19 17:55:37 -0400230 // Check that the size is a multiple of the size of the pointee type.
231 assert(Size % DstElemSize == 0);
David Neto22f144c2017-06-12 14:26:21 -0400232
alan-bakerbccf62c2019-03-29 10:32:41 -0400233 auto Alignment = cast<MemIntrinsic>(CI)->getDestAlignment();
David Netob84ba342017-06-19 17:55:37 -0400234 auto TypeAlignment = Layout.getABITypeAlignment(DstElemTy);
alan-baker4a757f62020-04-22 08:17:49 -0400235 (void)Alignment;
236 (void)TypeAlignment;
David Neto22f144c2017-06-12 14:26:21 -0400237
238 // Check that the alignment is at least the alignment of the pointee
239 // type.
240 assert(Alignment >= TypeAlignment);
241
242 // Check that the alignment is a multiple of the alignment of the
243 // pointee type.
244 assert(0 == (Alignment % TypeAlignment));
245
246 // Check that volatile is a constant.
alan-bakerbccf62c2019-03-29 10:32:41 -0400247 assert(isa<ConstantInt>(CI->getArgOperand(3)));
David Neto22f144c2017-06-12 14:26:21 -0400248
David Netob84ba342017-06-19 17:55:37 -0400249 CallsToReplaceWithSpirvCopyMemory.push_back(CI);
David Neto22f144c2017-06-12 14:26:21 -0400250 }
251 }
252
David Netob84ba342017-06-19 17:55:37 -0400253 for (auto CI : CallsToReplaceWithSpirvCopyMemory) {
alan-bakered80f572019-02-11 17:28:26 -0500254 auto Arg0 = dyn_cast<BitCastOperator>(CI->getArgOperand(0));
255 auto Arg1 = dyn_cast<BitCastOperator>(CI->getArgOperand(1));
David Neto22f144c2017-06-12 14:26:21 -0400256 auto Arg3 = dyn_cast<ConstantInt>(CI->getArgOperand(3));
David Neto22f144c2017-06-12 14:26:21 -0400257
258 auto I32Ty = Type::getInt32Ty(M.getContext());
Diego Novillo3cc8d7a2019-04-10 13:30:34 -0400259 auto Alignment =
260 ConstantInt::get(I32Ty, cast<MemIntrinsic>(CI)->getDestAlignment());
alan-bakerbccf62c2019-03-29 10:32:41 -0400261 auto Volatile = ConstantInt::get(I32Ty, Arg3->getZExtValue());
David Neto22f144c2017-06-12 14:26:21 -0400262
alan-bakered80f572019-02-11 17:28:26 -0500263 auto Dst = Arg0->getOperand(0);
264 auto Src = Arg1->getOperand(0);
David Netob84ba342017-06-19 17:55:37 -0400265
266 auto DstElemTy = Dst->getType()->getPointerElementType();
267 auto SrcElemTy = Src->getType()->getPointerElementType();
268 unsigned NumDstUnpackings = 0;
269 unsigned NumSrcUnpackings = 0;
David Netob84ba342017-06-19 17:55:37 -0400270 auto Size = dyn_cast<ConstantInt>(CI->getArgOperand(2))->getZExtValue();
Alan Baker7dea8842018-10-22 10:15:41 -0400271 match_types(*CI, Size, &DstElemTy, &SrcElemTy, &NumDstUnpackings,
272 &NumSrcUnpackings);
SJW61531372020-06-09 07:31:08 -0500273 auto SPIRVIntrinsic = clspv::CopyMemoryFunction();
David Neto22f144c2017-06-12 14:26:21 -0400274
David Netob84ba342017-06-19 17:55:37 -0400275 auto DstElemSize = Layout.getTypeSizeInBits(DstElemTy) / 8;
David Neto22f144c2017-06-12 14:26:21 -0400276
David Netob84ba342017-06-19 17:55:37 -0400277 IRBuilder<> Builder(CI);
278
279 if (NumSrcUnpackings == 0 && NumDstUnpackings == 0) {
280 auto NewFType = FunctionType::get(
281 F.getReturnType(), {Dst->getType(), Src->getType(), I32Ty, I32Ty},
282 false);
283 auto NewF =
284 Function::Create(NewFType, F.getLinkage(), SPIRVIntrinsic, &M);
285 Builder.CreateCall(NewF, {Dst, Src, Alignment, Volatile}, "");
286 } else {
287 auto Zero = ConstantInt::get(I32Ty, 0);
288 SmallVector<Value *, 3> SrcIndices;
289 SmallVector<Value *, 3> DstIndices;
290 // Make unpacking indices.
291 for (unsigned unpacking = 0; unpacking < NumSrcUnpackings;
292 ++unpacking) {
293 SrcIndices.push_back(Zero);
294 }
295 for (unsigned unpacking = 0; unpacking < NumDstUnpackings;
296 ++unpacking) {
297 DstIndices.push_back(Zero);
298 }
299 // Add a placeholder for the final index.
300 SrcIndices.push_back(Zero);
301 DstIndices.push_back(Zero);
302
303 // Build the function and function type only once.
Diego Novillo3cc8d7a2019-04-10 13:30:34 -0400304 FunctionType *NewFType = nullptr;
305 Function *NewF = nullptr;
David Netob84ba342017-06-19 17:55:37 -0400306
307 IRBuilder<> Builder(CI);
308 for (unsigned i = 0; i < Size / DstElemSize; ++i) {
309 auto Index = ConstantInt::get(I32Ty, i);
310 SrcIndices.back() = Index;
311 DstIndices.back() = Index;
312
alan-bakered80f572019-02-11 17:28:26 -0500313 // Avoid the builder for Src in order to prevent the folder from
314 // creating constant expressions for constant memcpys.
315 auto SrcElemPtr =
316 GetElementPtrInst::CreateInBounds(Src, SrcIndices, "", CI);
David Netob84ba342017-06-19 17:55:37 -0400317 auto DstElemPtr = Builder.CreateGEP(Dst, DstIndices);
318 NewFType =
319 NewFType != nullptr
320 ? NewFType
321 : FunctionType::get(F.getReturnType(),
322 {DstElemPtr->getType(),
323 SrcElemPtr->getType(), I32Ty, I32Ty},
324 false);
325 NewF = NewF != nullptr ? NewF
326 : Function::Create(NewFType, F.getLinkage(),
327 SPIRVIntrinsic, &M);
328 Builder.CreateCall(
329 NewF, {DstElemPtr, SrcElemPtr, Alignment, Volatile}, "");
330 }
331 }
332
333 // Erase the call.
David Neto22f144c2017-06-12 14:26:21 -0400334 CI->eraseFromParent();
335
David Netob84ba342017-06-19 17:55:37 -0400336 // Erase the bitcasts. A particular bitcast might be used
337 // in more than one memcpy, so defer actual deleting until later.
alan-bakered80f572019-02-11 17:28:26 -0500338 if (isa<BitCastInst>(Arg0))
339 BitCastsToForget.insert(dyn_cast<BitCastInst>(Arg0));
340 if (isa<BitCastInst>(Arg1))
341 BitCastsToForget.insert(dyn_cast<BitCastInst>(Arg1));
David Netob84ba342017-06-19 17:55:37 -0400342 }
Diego Novillo3cc8d7a2019-04-10 13:30:34 -0400343 for (auto *Inst : BitCastsToForget) {
David Netob84ba342017-06-19 17:55:37 -0400344 Inst->eraseFromParent();
David Neto22f144c2017-06-12 14:26:21 -0400345 }
346 }
347 }
348
349 return Changed;
350}
David Netoe345e0e2018-06-15 11:38:32 -0400351
352bool ReplaceLLVMIntrinsicsPass::removeLifetimeDeclarations(Module &M) {
353 // SPIR-V OpLifetimeStart and OpLifetimeEnd require Kernel capability.
354 // Vulkan doesn't support that, so remove all lifteime bounds declarations.
355
356 bool Changed = false;
357
358 SmallVector<Function *, 2> WorkList;
359 for (auto &F : M) {
360 if (F.getName().startswith("llvm.lifetime.")) {
361 WorkList.push_back(&F);
362 }
363 }
364
365 for (auto *F : WorkList) {
366 Changed = true;
alan-bakera5ff28e2018-11-21 16:27:20 -0500367 // Copy users to avoid modifying the list in place.
368 SmallVector<User *, 8> users(F->users());
369 for (auto U : users) {
David Netoe345e0e2018-06-15 11:38:32 -0400370 if (auto *CI = dyn_cast<CallInst>(U)) {
371 CI->eraseFromParent();
372 }
373 }
374 F->eraseFromParent();
375 }
376
377 return Changed;
378}