LLVM 23.0.0git
SPIRVLegalizePointerCast.cpp
Go to the documentation of this file.
1//===-- SPIRVLegalizePointerCast.cpp ----------------------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// The LLVM IR has multiple legal patterns we cannot lower to Logical SPIR-V.
10// This pass modifies such loads to have an IR we can directly lower to valid
11// logical SPIR-V.
12// OpenCL can avoid this because they rely on ptrcast, which is not supported
13// by logical SPIR-V.
14//
15// This pass relies on the assign_ptr_type intrinsic to deduce the type of the
16// pointed values, must replace all occurences of `ptrcast`. This is why
17// unhandled cases are reported as unreachable: we MUST cover all cases.
18//
19// 1. Loading the first element of an array
20//
21// %array = [10 x i32]
22// %value = load i32, ptr %array
23//
24// LLVM can skip the GEP instruction, and only request loading the first 4
25// bytes. In logical SPIR-V, we need an OpAccessChain to access the first
26// element. This pass will add a getelementptr instruction before the load.
27//
28//
29// 2. Implicit downcast from load
30//
31// %1 = getelementptr <4 x i32>, ptr %vec4, i64 0
32// %2 = load <3 x i32>, ptr %1
33//
34// The pointer in the GEP instruction is only used for offset computations,
35// but it doesn't NEED to match the pointed type. OpAccessChain however
36// requires this. Also, LLVM loads define the bitwidth of the load, not the
37// pointer. In this example, we can guess %vec4 is a vec4 thanks to the GEP
38// instruction basetype, but we only want to load the first 3 elements, hence
39// do a partial load. In logical SPIR-V, this is not legal. What we must do
40// is load the full vector (basetype), extract 3 elements, and recombine them
41// to form a 3-element vector.
42//
43//===----------------------------------------------------------------------===//
44
46#include "SPIRV.h"
47#include "SPIRVSubtarget.h"
48#include "SPIRVTargetMachine.h"
49#include "SPIRVUtils.h"
50#include "llvm/IR/IRBuilder.h"
52#include "llvm/IR/Intrinsics.h"
53#include "llvm/IR/IntrinsicsSPIRV.h"
56
57using namespace llvm;
58
59namespace {
60class SPIRVLegalizePointerCastImpl {
61
62 // Builds the `spv_assign_type` assigning |Ty| to |Value| at the current
63 // builder position.
64 void buildAssignType(IRBuilder<> &B, Type *Ty, Value *Arg) {
65 Value *OfType = PoisonValue::get(Ty);
66 CallInst *AssignCI = buildIntrWithMD(Intrinsic::spv_assign_type,
67 {Arg->getType()}, OfType, Arg, {}, B);
68 GR->addAssignPtrTypeInstr(Arg, AssignCI);
69 }
70
71 static FixedVectorType *makeVectorFromTotalBits(Type *ElemTy,
72 TypeSize TotalBits) {
73 unsigned ElemBits = ElemTy->getScalarSizeInBits();
74 assert(ElemBits && TotalBits % ElemBits == 0 &&
75 "TotalBits must be divisible by element bit size");
76 return FixedVectorType::get(ElemTy, TotalBits / ElemBits);
77 }
78
79 Value *resizeVectorBitsWithShuffle(IRBuilder<> &B, Value *V,
80 FixedVectorType *DstTy) {
81 auto *SrcTy = cast<FixedVectorType>(V->getType());
82 assert(SrcTy->getElementType() == DstTy->getElementType() &&
83 "shuffle resize expects identical element types");
84
85 const unsigned NumNeeded = DstTy->getNumElements();
86 const unsigned NumSource = SrcTy->getNumElements();
87
88 SmallVector<int> Mask(NumNeeded);
89 for (unsigned I = 0; I < NumNeeded; ++I)
90 Mask[I] = (I < NumSource) ? static_cast<int>(I) : -1;
91
92 Value *Resized = B.CreateShuffleVector(V, V, Mask);
93 buildAssignType(B, DstTy, Resized);
94 return Resized;
95 }
96
97 // Loads parts of the vector of type |SourceType| from the pointer |Source|
98 // and create a new vector of type |TargetType|. |TargetType| must be a vector
99 // type.
100 // Returns the loaded value.
101 Value *loadVectorFromVector(IRBuilder<> &B, FixedVectorType *SourceType,
102 FixedVectorType *TargetType, Value *Source) {
103 LoadInst *NewLoad = B.CreateLoad(SourceType, Source);
104 buildAssignType(B, SourceType, NewLoad);
105 Value *AssignValue = NewLoad;
106 if (TargetType->getElementType() != SourceType->getElementType()) {
107 const DataLayout &DL = B.GetInsertBlock()->getModule()->getDataLayout();
108 TypeSize TargetTypeSize = DL.getTypeSizeInBits(TargetType);
109 TypeSize SourceTypeSize = DL.getTypeSizeInBits(SourceType);
110
111 Value *BitcastSrcVal = NewLoad;
112 FixedVectorType *BitcastSrcTy =
113 cast<FixedVectorType>(BitcastSrcVal->getType());
114 FixedVectorType *BitcastDstTy = TargetType;
115
116 if (TargetTypeSize != SourceTypeSize) {
117 unsigned TargetElemBits =
118 TargetType->getElementType()->getScalarSizeInBits();
119 if (SourceTypeSize % TargetElemBits == 0) {
120 // No Resize needed. Same total bits as source, but use target element
121 // type.
122 BitcastDstTy = makeVectorFromTotalBits(TargetType->getElementType(),
123 SourceTypeSize);
124 } else {
125 // Resize source to target total bitwidth using source element type.
126 BitcastSrcTy = makeVectorFromTotalBits(SourceType->getElementType(),
127 TargetTypeSize);
128 BitcastSrcVal = resizeVectorBitsWithShuffle(B, NewLoad, BitcastSrcTy);
129 }
130 }
131 AssignValue =
132 B.CreateIntrinsic(Intrinsic::spv_bitcast,
133 {BitcastDstTy, BitcastSrcTy}, {BitcastSrcVal});
134 buildAssignType(B, BitcastDstTy, AssignValue);
135 if (BitcastDstTy == TargetType)
136 return AssignValue;
137 }
138
139 assert(TargetType->getNumElements() < SourceType->getNumElements());
140 SmallVector<int> Mask(/* Size= */ TargetType->getNumElements());
141 for (unsigned I = 0; I < TargetType->getNumElements(); ++I)
142 Mask[I] = I;
143 Value *Output = B.CreateShuffleVector(AssignValue, AssignValue, Mask);
144 buildAssignType(B, TargetType, Output);
145 return Output;
146 }
147
148 // Loads the first value in an aggregate pointed by |Source| of containing
149 // elements of type |ElementType|. Load flags will be copied from |BadLoad|,
150 // which should be the load being legalized. Returns the loaded value.
151 Value *loadFirstValueFromAggregate(IRBuilder<> &B, Type *ElementType,
152 Value *Source, LoadInst *BadLoad) {
153 std::array<Type *, 2> Types = {BadLoad->getPointerOperandType(),
154 Source->getType()};
155 SmallVector<Value *, 8> Args{/* isInBounds= */ B.getInt1(false), Source};
156
157 Type *AggregateType = GR->findDeducedElementType(Source);
158 assert(AggregateType && "Could not deduce aggregate type");
159 buildGEPIndexChain(B, ElementType, AggregateType, Args);
160
161 auto *GEP = B.CreateIntrinsic(Intrinsic::spv_gep, {Types}, {Args});
162 GR->buildAssignPtr(B, ElementType, GEP);
163
164 LoadInst *LI = B.CreateLoad(ElementType, GEP);
165 LI->setAlignment(BadLoad->getAlign());
166 buildAssignType(B, ElementType, LI);
167 return LI;
168 }
169 Value *
170 buildVectorFromLoadedElements(IRBuilder<> &B, FixedVectorType *TargetType,
171 SmallVector<Value *, 4> &LoadedElements) {
172 // Build the vector from the loaded elements.
173 Value *NewVector = PoisonValue::get(TargetType);
174 buildAssignType(B, TargetType, NewVector);
175
176 for (unsigned I = 0, E = TargetType->getNumElements(); I < E; ++I) {
177 Value *Index = B.getInt32(I);
178 SmallVector<Type *, 4> Types = {TargetType, TargetType,
179 TargetType->getElementType(),
180 Index->getType()};
181 SmallVector<Value *> Args = {NewVector, LoadedElements[I], Index};
182 NewVector = B.CreateIntrinsic(Intrinsic::spv_insertelt, {Types}, {Args});
183 buildAssignType(B, TargetType, NewVector);
184 }
185 return NewVector;
186 }
187
188 // Loads elements from a matrix with an array of vector memory layout and
189 // constructs a vector.
190 Value *loadVectorFromMatrixArray(IRBuilder<> &B, FixedVectorType *TargetType,
191 Value *Source,
192 FixedVectorType *ArrElemVecTy) {
193 Type *TargetElemTy = TargetType->getElementType();
194 unsigned ScalarsPerArrayElement = ArrElemVecTy->getNumElements();
195 // Load each element of the array.
196 SmallVector<Value *, 4> LoadedElements;
197 std::array<Type *, 2> Types = {Source->getType(), Source->getType()};
198 for (unsigned I = 0, E = TargetType->getNumElements(); I < E; ++I) {
199 unsigned ArrayIndex = I / ScalarsPerArrayElement;
200 unsigned ElementIndexInArrayElem = I % ScalarsPerArrayElement;
201 // Create a GEP to access the i-th element of the array.
202 std::array<Value *, 4> Args = {
203 B.getInt1(/*Inbounds=*/false), Source, B.getInt32(0),
204 ConstantInt::get(B.getInt32Ty(), ArrayIndex)};
205 auto *ElementPtr = B.CreateIntrinsic(Intrinsic::spv_gep, {Types}, {Args});
206 GR->buildAssignPtr(B, ArrElemVecTy, ElementPtr);
207 Value *LoadVec = B.CreateLoad(ArrElemVecTy, ElementPtr);
208 buildAssignType(B, ArrElemVecTy, LoadVec);
209 LoadedElements.push_back(makeExtractElement(B, TargetElemTy, LoadVec,
210 ElementIndexInArrayElem));
211 }
212 return buildVectorFromLoadedElements(B, TargetType, LoadedElements);
213 }
214 // Loads elements from an array and constructs a vector.
215 Value *loadVectorFromArray(IRBuilder<> &B, FixedVectorType *TargetType,
216 Value *Source) {
217 // Load each element of the array.
218 SmallVector<Value *, 4> LoadedElements;
219 std::array<Type *, 2> Types = {Source->getType(), Source->getType()};
220 for (unsigned I = 0, E = TargetType->getNumElements(); I < E; ++I) {
221 // Create a GEP to access the i-th element of the array.
222 std::array<Value *, 4> Args = {B.getInt1(/*Inbounds=*/false), Source,
223 B.getInt32(0),
224 ConstantInt::get(B.getInt32Ty(), I)};
225 auto *ElementPtr = B.CreateIntrinsic(Intrinsic::spv_gep, {Types}, {Args});
226 GR->buildAssignPtr(B, TargetType->getElementType(), ElementPtr);
227
228 // Load the value from the element pointer.
229 Value *Load = B.CreateLoad(TargetType->getElementType(), ElementPtr);
230 buildAssignType(B, TargetType->getElementType(), Load);
231 LoadedElements.push_back(Load);
232 }
233 return buildVectorFromLoadedElements(B, TargetType, LoadedElements);
234 }
235
236 // Stores elements from a vector into a matrix (an array of vectors).
237 void storeMatrixArrayFromVector(IRBuilder<> &B, Value *SrcVector,
238 Value *DstArrayPtr, ArrayType *ArrTy,
239 Align Alignment) {
240 auto *SrcVecTy = cast<FixedVectorType>(SrcVector->getType());
241 auto *ArrElemVecTy = cast<FixedVectorType>(ArrTy->getElementType());
242 Type *ElemTy = ArrElemVecTy->getElementType();
243 unsigned ScalarsPerArrayElement = ArrElemVecTy->getNumElements();
244 unsigned SrcNumElements = SrcVecTy->getNumElements();
245 assert(
246 SrcNumElements % ScalarsPerArrayElement == 0 &&
247 "Source vector size must be a multiple of array element vector size");
248
249 std::array<Type *, 2> Types = {DstArrayPtr->getType(),
250 DstArrayPtr->getType()};
251
252 for (unsigned I = 0; I < SrcNumElements; I += ScalarsPerArrayElement) {
253 unsigned ArrayIndex = I / ScalarsPerArrayElement;
254 // Create a GEP to access the array element.
255 std::array<Value *, 4> Args = {
256 B.getInt1(/*Inbounds=*/false), DstArrayPtr, B.getInt32(0),
257 ConstantInt::get(B.getInt32Ty(), ArrayIndex)};
258 auto *ElementPtr = B.CreateIntrinsic(Intrinsic::spv_gep, {Types}, {Args});
259 GR->buildAssignPtr(B, ArrElemVecTy, ElementPtr);
260
261 // Extract scalar elements from the source vector for this array slot.
262 SmallVector<Value *, 4> Elements;
263 for (unsigned J = 0; J < ScalarsPerArrayElement; ++J)
264 Elements.push_back(makeExtractElement(B, ElemTy, SrcVector, I + J));
265
266 // Build a vector from the extracted elements and store it.
267 Value *Vec = buildVectorFromLoadedElements(B, ArrElemVecTy, Elements);
268 StoreInst *SI = B.CreateStore(Vec, ElementPtr);
269 SI->setAlignment(Alignment);
270 }
271 }
272
273 // Stores elements from a vector into an array.
274 void storeArrayFromVector(IRBuilder<> &B, Value *SrcVector,
275 Value *DstArrayPtr, ArrayType *ArrTy,
276 Align Alignment) {
277 auto *VecTy = cast<FixedVectorType>(SrcVector->getType());
278 Type *ElemTy = ArrTy->getElementType();
279
280 // Ensure the element types of the array and vector are the same.
281 assert(VecTy->getElementType() == ElemTy &&
282 "Element types of array and vector must be the same.");
283 std::array<Type *, 2> Types = {DstArrayPtr->getType(),
284 DstArrayPtr->getType()};
285
286 for (unsigned I = 0, E = VecTy->getNumElements(); I < E; ++I) {
287 // Create a GEP to access the i-th element of the array.
288 std::array<Value *, 4> Args = {B.getInt1(/*Inbounds=*/false), DstArrayPtr,
289 B.getInt32(0),
290 ConstantInt::get(B.getInt32Ty(), I)};
291 auto *ElementPtr = B.CreateIntrinsic(Intrinsic::spv_gep, {Types}, {Args});
292 GR->buildAssignPtr(B, ElemTy, ElementPtr);
293
294 // Extract the element from the vector and store it.
295 Value *Element = makeExtractElement(B, ElemTy, SrcVector, I);
296 StoreInst *SI = B.CreateStore(Element, ElementPtr);
297 SI->setAlignment(Alignment);
298 }
299 }
300
301 // Replaces the load instruction to get rid of the ptrcast used as source
302 // operand.
303 void transformLoad(IRBuilder<> &B, LoadInst *LI, Value *CastedOperand,
304 Value *OriginalOperand) {
305 Type *FromTy = GR->findDeducedElementType(OriginalOperand);
306 Type *ToTy = GR->findDeducedElementType(CastedOperand);
307 Value *Output = nullptr;
308
309 auto *SAT = dyn_cast<ArrayType>(FromTy);
310 auto *SVT = dyn_cast<FixedVectorType>(FromTy);
311 auto *DVT = dyn_cast<FixedVectorType>(ToTy);
312 auto *MAT =
313 SAT ? dyn_cast<FixedVectorType>(SAT->getElementType()) : nullptr;
314
315 B.SetInsertPoint(LI);
316
317 // Destination is the element type of some member of FromTy. For example,
318 // loading the 1st element of an array:
319 // - float a = array[0];
320 if (isTypeFirstElementAggregate(ToTy, FromTy))
321 Output = loadFirstValueFromAggregate(B, ToTy, OriginalOperand, LI);
322 // Destination is a smaller vector than source or different vector type.
323 // - float3 v3 = vector4;
324 // - float4 v2 = int4;
325 else if (SVT && DVT)
326 Output = loadVectorFromVector(B, SVT, DVT, OriginalOperand);
327 else if (SAT && DVT && SAT->getElementType() == DVT->getElementType())
328 Output = loadVectorFromArray(B, DVT, OriginalOperand);
329 else if (MAT && DVT && MAT->getElementType() == DVT->getElementType())
330 Output = loadVectorFromMatrixArray(B, DVT, OriginalOperand, MAT);
331 else
332 llvm_unreachable("Unimplemented implicit down-cast from load.");
333
334 GR->replaceAllUsesWith(LI, Output, /* DeleteOld= */ true);
335 DeadInstructions.push_back(LI);
336 }
337
338 // Creates an spv_insertelt instruction (equivalent to llvm's insertelement).
339 Value *makeInsertElement(IRBuilder<> &B, Value *Vector, Value *Element,
340 unsigned Index) {
341 Type *Int32Ty = Type::getInt32Ty(B.getContext());
342 SmallVector<Type *, 4> Types = {Vector->getType(), Vector->getType(),
343 Element->getType(), Int32Ty};
344 SmallVector<Value *> Args = {Vector, Element, B.getInt32(Index)};
345 Instruction *NewI =
346 B.CreateIntrinsic(Intrinsic::spv_insertelt, {Types}, {Args});
347 buildAssignType(B, Vector->getType(), NewI);
348 return NewI;
349 }
350
351 // Creates an spv_extractelt instruction (equivalent to llvm's
352 // extractelement).
353 Value *makeExtractElement(IRBuilder<> &B, Type *ElementType, Value *Vector,
354 unsigned Index) {
355 Type *Int32Ty = Type::getInt32Ty(B.getContext());
357 SmallVector<Value *> Args = {Vector, B.getInt32(Index)};
358 Instruction *NewI =
359 B.CreateIntrinsic(Intrinsic::spv_extractelt, {Types}, {Args});
360 buildAssignType(B, ElementType, NewI);
361 return NewI;
362 }
363
364 // Stores the given Src vector operand into the Dst vector, adjusting the size
365 // if required.
366 Value *storeVectorFromVector(IRBuilder<> &B, Value *Src, Value *Dst,
367 Align Alignment) {
368 FixedVectorType *SrcType = cast<FixedVectorType>(Src->getType());
369 FixedVectorType *DstType =
370 cast<FixedVectorType>(GR->findDeducedElementType(Dst));
371 auto dstNumElements = DstType->getNumElements();
372 auto srcNumElements = SrcType->getNumElements();
373
374 // if the element type differs, it is a bitcast.
375 if (DstType->getElementType() != SrcType->getElementType()) {
376 // Support bitcast between vectors of different sizes only if
377 // the total bitwidth is the same.
378 [[maybe_unused]] auto dstBitWidth =
379 DstType->getElementType()->getScalarSizeInBits() * dstNumElements;
380 [[maybe_unused]] auto srcBitWidth =
381 SrcType->getElementType()->getScalarSizeInBits() * srcNumElements;
382 assert(dstBitWidth == srcBitWidth &&
383 "Unsupported bitcast between vectors of different sizes.");
384
385 Src =
386 B.CreateIntrinsic(Intrinsic::spv_bitcast, {DstType, SrcType}, {Src});
387 buildAssignType(B, DstType, Src);
388 SrcType = DstType;
389
390 StoreInst *SI = B.CreateStore(Src, Dst);
391 SI->setAlignment(Alignment);
392 return SI;
393 }
394
395 assert(DstType->getNumElements() >= SrcType->getNumElements());
396 LoadInst *LI = B.CreateLoad(DstType, Dst);
397 LI->setAlignment(Alignment);
398 Value *OldValues = LI;
399 buildAssignType(B, OldValues->getType(), OldValues);
400 Value *NewValues = Src;
401
402 for (unsigned I = 0; I < SrcType->getNumElements(); ++I) {
403 Value *Element =
404 makeExtractElement(B, SrcType->getElementType(), NewValues, I);
405 OldValues = makeInsertElement(B, OldValues, Element, I);
406 }
407
408 StoreInst *SI = B.CreateStore(OldValues, Dst);
409 SI->setAlignment(Alignment);
410 return SI;
411 }
412
413 void buildGEPIndexChain(IRBuilder<> &B, Type *Search, Type *Aggregate,
414 SmallVectorImpl<Value *> &Indices) {
415 Indices.push_back(B.getInt32(0));
416
417 if (Search == Aggregate)
418 return;
419
420 if (auto *ST = dyn_cast<StructType>(Aggregate))
421 buildGEPIndexChain(B, Search, ST->getTypeAtIndex(0u), Indices);
422 else if (auto *AT = dyn_cast<ArrayType>(Aggregate))
423 buildGEPIndexChain(B, Search, AT->getElementType(), Indices);
424 else if (auto *VT = dyn_cast<FixedVectorType>(Aggregate))
425 buildGEPIndexChain(B, Search, VT->getElementType(), Indices);
426 else
427 llvm_unreachable("Bad access chain?");
428 }
429
430 // Stores the given Src value into the first entry of the Dst aggregate.
431 Value *storeToFirstValueAggregate(IRBuilder<> &B, Value *Src, Value *Dst,
432 Type *DstPointeeType, Align Alignment) {
433 std::array<Type *, 2> Types = {Dst->getType(), Dst->getType()};
434 SmallVector<Value *, 8> Args{/* isInBounds= */ B.getInt1(true), Dst};
435 buildGEPIndexChain(B, Src->getType(), DstPointeeType, Args);
436 auto *GEP = B.CreateIntrinsic(Intrinsic::spv_gep, {Types}, {Args});
437 GR->buildAssignPtr(B, Src->getType(), GEP);
438 StoreInst *SI = B.CreateStore(Src, GEP);
439 SI->setAlignment(Alignment);
440 return SI;
441 }
442
443 bool isTypeFirstElementAggregate(Type *Search, Type *Aggregate) {
444 if (Search == Aggregate)
445 return true;
446 if (auto *ST = dyn_cast<StructType>(Aggregate))
447 return isTypeFirstElementAggregate(Search, ST->getTypeAtIndex(0u));
448 if (auto *VT = dyn_cast<FixedVectorType>(Aggregate))
449 return isTypeFirstElementAggregate(Search, VT->getElementType());
450 if (auto *AT = dyn_cast<ArrayType>(Aggregate))
451 return isTypeFirstElementAggregate(Search, AT->getElementType());
452 return false;
453 }
454
455 // Transforms a store instruction (or SPV intrinsic) using a ptrcast as
456 // operand into a valid logical SPIR-V store with no ptrcast.
457 void transformStore(IRBuilder<> &B, Instruction *BadStore, Value *Src,
458 Value *Dst, Align Alignment) {
459 Type *ToTy = GR->findDeducedElementType(Dst);
460 Type *FromTy = Src->getType();
461
462 auto *S_VT = dyn_cast<FixedVectorType>(FromTy);
463 auto *D_VT = dyn_cast<FixedVectorType>(ToTy);
464 auto *D_AT = dyn_cast<ArrayType>(ToTy);
465 auto *D_MAT =
466 D_AT ? dyn_cast<FixedVectorType>(D_AT->getElementType()) : nullptr;
467
468 B.SetInsertPoint(BadStore);
469 if (isTypeFirstElementAggregate(FromTy, ToTy))
470 storeToFirstValueAggregate(B, Src, Dst, ToTy, Alignment);
471 else if (D_VT && S_VT)
472 storeVectorFromVector(B, Src, Dst, Alignment);
473 else if (D_VT && !S_VT && FromTy == D_VT->getElementType())
474 storeToFirstValueAggregate(B, Src, Dst, D_VT, Alignment);
475 else if (D_AT && S_VT && S_VT->getElementType() == D_AT->getElementType())
476 storeArrayFromVector(B, Src, Dst, D_AT, Alignment);
477 else if (D_MAT && S_VT && D_MAT->getElementType() == S_VT->getElementType())
478 storeMatrixArrayFromVector(B, Src, Dst, D_AT, Alignment);
479 else
480 llvm_unreachable("Unsupported ptrcast use in store. Please fix.");
481
482 DeadInstructions.push_back(BadStore);
483 }
484
485 void legalizePointerCast(IntrinsicInst *II) {
486 Value *CastedOperand = II;
487 Value *OriginalOperand = II->getOperand(0);
488
489 IRBuilder<> B(II->getContext());
490 std::vector<Value *> Users;
491 for (Use &U : II->uses())
492 Users.push_back(U.getUser());
493
494 for (Value *User : Users) {
495 if (LoadInst *LI = dyn_cast<LoadInst>(User)) {
496 transformLoad(B, LI, CastedOperand, OriginalOperand);
497 continue;
498 }
499
500 if (StoreInst *SI = dyn_cast<StoreInst>(User)) {
501 transformStore(B, SI, SI->getValueOperand(), OriginalOperand,
502 SI->getAlign());
503 continue;
504 }
505
506 if (IntrinsicInst *Intrin = dyn_cast<IntrinsicInst>(User)) {
507 if (Intrin->getIntrinsicID() == Intrinsic::spv_assign_ptr_type) {
508 DeadInstructions.push_back(Intrin);
509 continue;
510 }
511
512 if (Intrin->getIntrinsicID() == Intrinsic::spv_gep) {
513 GR->replaceAllUsesWith(CastedOperand, OriginalOperand,
514 /* DeleteOld= */ false);
515 continue;
516 }
517
518 if (Intrin->getIntrinsicID() == Intrinsic::spv_store) {
519 Align Alignment;
520 if (ConstantInt *C = dyn_cast<ConstantInt>(Intrin->getOperand(3)))
521 Alignment = Align(C->getZExtValue());
522 transformStore(B, Intrin, Intrin->getArgOperand(0), OriginalOperand,
523 Alignment);
524 continue;
525 }
526 }
527
528 llvm_unreachable("Unsupported ptrcast user. Please fix.");
529 }
530
531 DeadInstructions.push_back(II);
532 }
533
534public:
535 SPIRVLegalizePointerCastImpl(const SPIRVTargetMachine &TM) : TM(TM) {}
536
537 bool run(Function &F) {
538 const SPIRVSubtarget &ST = TM.getSubtarget<SPIRVSubtarget>(F);
539 GR = ST.getSPIRVGlobalRegistry();
540 DeadInstructions.clear();
541
542 std::vector<IntrinsicInst *> WorkList;
543 for (auto &BB : F) {
544 for (auto &I : BB) {
545 auto *II = dyn_cast<IntrinsicInst>(&I);
546 if (II && II->getIntrinsicID() == Intrinsic::spv_ptrcast)
547 WorkList.push_back(II);
548 }
549 }
550
551 for (IntrinsicInst *II : WorkList)
552 legalizePointerCast(II);
553
554 for (Instruction *I : DeadInstructions)
555 I->eraseFromParent();
556
557 return DeadInstructions.size() != 0;
558 }
559
560private:
561 const SPIRVTargetMachine &TM;
562 SPIRVGlobalRegistry *GR = nullptr;
563 std::vector<Instruction *> DeadInstructions;
564};
565
566class SPIRVLegalizePointerCastLegacy : public FunctionPass {
567public:
568 static char ID;
569 SPIRVLegalizePointerCastLegacy(const SPIRVTargetMachine &TM)
570 : FunctionPass(ID), TM(TM) {}
571
572 bool runOnFunction(Function &F) override {
573 return SPIRVLegalizePointerCastImpl(TM).run(F);
574 }
575
576private:
577 const SPIRVTargetMachine &TM;
578};
579} // namespace
580
583 return SPIRVLegalizePointerCastImpl(TM).run(F) ? PreservedAnalyses::none()
585}
586
587char SPIRVLegalizePointerCastLegacy::ID = 0;
588INITIALIZE_PASS(SPIRVLegalizePointerCastLegacy, "spirv-legalize-pointer-cast",
589 "SPIRV legalize pointer cast pass", false, false)
590
592 return new SPIRVLegalizePointerCastLegacy(*TM);
593}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static bool runOnFunction(Function &F, bool PostInlining)
Hexagon Common GEP
iv Induction Variable Users
Definition IVUsers.cpp:48
#define F(x, y, z)
Definition MD5.cpp:54
#define I(x, y, z)
Definition MD5.cpp:57
uint64_t IntrinsicInst * II
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
Definition PassSupport.h:56
unsigned getNumElements() const
static LLVM_ABI FixedVectorType * get(Type *ElementType, unsigned NumElts)
Definition Type.cpp:873
FunctionPass class - This class is used to implement most global optimizations.
Definition Pass.h:314
void setAlignment(Align Align)
Type * getPointerOperandType() const
Align getAlign() const
Return the alignment of the access that is being performed.
static LLVM_ABI PoisonValue * get(Type *T)
Static factory methods - Return an 'poison' object of the specified type.
A set of analyses that are preserved following a run of a transformation pass.
Definition Analysis.h:112
static PreservedAnalyses none()
Convenience factory function for the empty preserved set.
Definition Analysis.h:115
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
Definition Analysis.h:118
PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM)
void push_back(const T &Elt)
LLVM_ABI unsigned getScalarSizeInBits() const LLVM_READONLY
If this is a vector type, return the getPrimitiveSizeInBits value for the element type.
Definition Type.cpp:236
Type * getType() const
All values are typed, get the type of this value.
Definition Value.h:255
Type * getElementType() const
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
constexpr char Align[]
Key for Kernel::Arg::Metadata::mAlign.
constexpr char Args[]
Key for Kernel::Metadata::mArgs.
constexpr std::underlying_type_t< E > Mask()
Get a bitmask with 1s in all places up to the high-order bit of E's largest value.
@ C
The default llvm calling convention, compatible with C.
Definition CallingConv.h:34
PointerTypeMap run(const Module &M)
Compute the PointerTypeMap for the module M.
ElementType
The element type of an SRV or UAV resource.
Definition DXILABI.h:68
friend class Instruction
Iterator for Instructions in a `BasicBlock.
Definition BasicBlock.h:73
This is an optimization pass for GlobalISel generic memory operations.
FunctionAddr VTableAddr Value
Definition InstrProf.h:137
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
FunctionAddr VTableAddr uintptr_t uintptr_t Int32Ty
Definition InstrProf.h:328
CallInst * buildIntrWithMD(Intrinsic::ID IntrID, ArrayRef< Type * > Types, Value *Arg, Value *Arg2, ArrayRef< Constant * > Imms, IRBuilder<> &B)
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
IRBuilder(LLVMContext &, FolderTy, InserterTy, MDNode *, ArrayRef< OperandBundleDef >) -> IRBuilder< FolderTy, InserterTy >
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:559
AnalysisManager< Function > FunctionAnalysisManager
Convenience typedef for the Function analysis manager.
FunctionPass * createSPIRVLegalizePointerCastPass(SPIRVTargetMachine *TM)