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
45#include "SPIRV.h"
46#include "SPIRVSubtarget.h"
47#include "SPIRVTargetMachine.h"
48#include "SPIRVUtils.h"
49#include "llvm/IR/IRBuilder.h"
50#include "llvm/IR/IntrinsicInst.h"
51#include "llvm/IR/Intrinsics.h"
52#include "llvm/IR/IntrinsicsSPIRV.h"
53#include "llvm/Transforms/Utils/Cloning.h"
54#include "llvm/Transforms/Utils/LowerMemIntrinsics.h"
55
56using namespace llvm;
57
58namespace {
59class SPIRVLegalizePointerCast : public FunctionPass {
60
61 // Builds the `spv_assign_type` assigning |Ty| to |Value| at the current
62 // builder position.
63 void buildAssignType(IRBuilder<> &B, Type *Ty, Value *Arg) {
64 Value *OfType = PoisonValue::get(T: Ty);
65 CallInst *AssignCI = buildIntrWithMD(IntrID: Intrinsic::spv_assign_type,
66 Types: {Arg->getType()}, Arg: OfType, Arg2: Arg, Imms: {}, B);
67 GR->addAssignPtrTypeInstr(Val: Arg, AssignPtrTyCI: AssignCI);
68 }
69
70 static FixedVectorType *makeVectorFromTotalBits(Type *ElemTy,
71 TypeSize TotalBits) {
72 unsigned ElemBits = ElemTy->getScalarSizeInBits();
73 assert(ElemBits && TotalBits % ElemBits == 0 &&
74 "TotalBits must be divisible by element bit size");
75 return FixedVectorType::get(ElementType: ElemTy, NumElts: TotalBits / ElemBits);
76 }
77
78 Value *resizeVectorBitsWithShuffle(IRBuilder<> &B, Value *V,
79 FixedVectorType *DstTy) {
80 auto *SrcTy = cast<FixedVectorType>(Val: V->getType());
81 assert(SrcTy->getElementType() == DstTy->getElementType() &&
82 "shuffle resize expects identical element types");
83
84 const unsigned NumNeeded = DstTy->getNumElements();
85 const unsigned NumSource = SrcTy->getNumElements();
86
87 SmallVector<int> Mask(NumNeeded);
88 for (unsigned I = 0; I < NumNeeded; ++I)
89 Mask[I] = (I < NumSource) ? static_cast<int>(I) : -1;
90
91 Value *Resized = B.CreateShuffleVector(V1: V, V2: V, Mask);
92 buildAssignType(B, Ty: DstTy, Arg: Resized);
93 return Resized;
94 }
95
96 // Loads parts of the vector of type |SourceType| from the pointer |Source|
97 // and create a new vector of type |TargetType|. |TargetType| must be a vector
98 // type.
99 // Returns the loaded value.
100 Value *loadVectorFromVector(IRBuilder<> &B, FixedVectorType *SourceType,
101 FixedVectorType *TargetType, Value *Source) {
102 LoadInst *NewLoad = B.CreateLoad(Ty: SourceType, Ptr: Source);
103 buildAssignType(B, Ty: SourceType, Arg: NewLoad);
104 Value *AssignValue = NewLoad;
105 if (TargetType->getElementType() != SourceType->getElementType()) {
106 const DataLayout &DL = B.GetInsertBlock()->getModule()->getDataLayout();
107 TypeSize TargetTypeSize = DL.getTypeSizeInBits(Ty: TargetType);
108 TypeSize SourceTypeSize = DL.getTypeSizeInBits(Ty: SourceType);
109
110 Value *BitcastSrcVal = NewLoad;
111 FixedVectorType *BitcastSrcTy =
112 cast<FixedVectorType>(Val: BitcastSrcVal->getType());
113 FixedVectorType *BitcastDstTy = TargetType;
114
115 if (TargetTypeSize != SourceTypeSize) {
116 unsigned TargetElemBits =
117 TargetType->getElementType()->getScalarSizeInBits();
118 if (SourceTypeSize % TargetElemBits == 0) {
119 // No Resize needed. Same total bits as source, but use target element
120 // type.
121 BitcastDstTy = makeVectorFromTotalBits(ElemTy: TargetType->getElementType(),
122 TotalBits: SourceTypeSize);
123 } else {
124 // Resize source to target total bitwidth using source element type.
125 BitcastSrcTy = makeVectorFromTotalBits(ElemTy: SourceType->getElementType(),
126 TotalBits: TargetTypeSize);
127 BitcastSrcVal = resizeVectorBitsWithShuffle(B, V: NewLoad, DstTy: BitcastSrcTy);
128 }
129 }
130 AssignValue =
131 B.CreateIntrinsic(ID: Intrinsic::spv_bitcast,
132 Types: {BitcastDstTy, BitcastSrcTy}, Args: {BitcastSrcVal});
133 buildAssignType(B, Ty: BitcastDstTy, Arg: AssignValue);
134 if (BitcastDstTy == TargetType)
135 return AssignValue;
136 }
137
138 assert(TargetType->getNumElements() < SourceType->getNumElements());
139 SmallVector<int> Mask(/* Size= */ TargetType->getNumElements());
140 for (unsigned I = 0; I < TargetType->getNumElements(); ++I)
141 Mask[I] = I;
142 Value *Output = B.CreateShuffleVector(V1: AssignValue, V2: AssignValue, Mask);
143 buildAssignType(B, Ty: TargetType, Arg: Output);
144 return Output;
145 }
146
147 // Loads the first value in an aggregate pointed by |Source| of containing
148 // elements of type |ElementType|. Load flags will be copied from |BadLoad|,
149 // which should be the load being legalized. Returns the loaded value.
150 Value *loadFirstValueFromAggregate(IRBuilder<> &B, Type *ElementType,
151 Value *Source, LoadInst *BadLoad) {
152 SmallVector<Type *, 2> Types = {BadLoad->getPointerOperandType(),
153 Source->getType()};
154 SmallVector<Value *, 8> Args{/* isInBounds= */ B.getInt1(V: false), Source};
155
156 Type *AggregateType = GR->findDeducedElementType(Val: Source);
157 assert(AggregateType && "Could not deduce aggregate type");
158 buildGEPIndexChain(B, Search: ElementType, Aggregate: AggregateType, Indices&: Args);
159
160 auto *GEP = B.CreateIntrinsic(ID: Intrinsic::spv_gep, Types: {Types}, Args: {Args});
161 GR->buildAssignPtr(B, ElemTy: ElementType, Arg: GEP);
162
163 LoadInst *LI = B.CreateLoad(Ty: ElementType, Ptr: GEP);
164 LI->setAlignment(BadLoad->getAlign());
165 buildAssignType(B, Ty: ElementType, Arg: LI);
166 return LI;
167 }
168 Value *
169 buildVectorFromLoadedElements(IRBuilder<> &B, FixedVectorType *TargetType,
170 SmallVector<Value *, 4> &LoadedElements) {
171 // Build the vector from the loaded elements.
172 Value *NewVector = PoisonValue::get(T: TargetType);
173 buildAssignType(B, Ty: TargetType, Arg: NewVector);
174
175 for (unsigned I = 0; I < TargetType->getNumElements(); ++I) {
176 Value *Index = B.getInt32(C: I);
177 SmallVector<Type *, 4> Types = {TargetType, TargetType,
178 TargetType->getElementType(),
179 Index->getType()};
180 SmallVector<Value *> Args = {NewVector, LoadedElements[I], Index};
181 NewVector = B.CreateIntrinsic(ID: Intrinsic::spv_insertelt, Types: {Types}, Args: {Args});
182 buildAssignType(B, Ty: TargetType, Arg: NewVector);
183 }
184 return NewVector;
185 }
186
187 // Loads elements from a matrix with an array of vector memory layout and
188 // constructs a vector.
189 Value *loadVectorFromMatrixArray(IRBuilder<> &B, FixedVectorType *TargetType,
190 Value *Source,
191 FixedVectorType *ArrElemVecTy) {
192 Type *TargetElemTy = TargetType->getElementType();
193 unsigned ScalarsPerArrayElement = ArrElemVecTy->getNumElements();
194 // Load each element of the array.
195 SmallVector<Value *, 4> LoadedElements;
196 SmallVector<Type *, 2> Types = {Source->getType(), Source->getType()};
197 for (unsigned I = 0; I < TargetType->getNumElements(); ++I) {
198 unsigned ArrayIndex = I / ScalarsPerArrayElement;
199 unsigned ElementIndexInArrayElem = I % ScalarsPerArrayElement;
200 // Create a GEP to access the i-th element of the array.
201 SmallVector<Value *, 4> Args;
202 Args.push_back(Elt: B.getInt1(/*Inbounds=*/V: false));
203 Args.push_back(Elt: Source);
204 Args.push_back(Elt: B.getInt32(C: 0));
205 Args.push_back(Elt: ConstantInt::get(Ty: B.getInt32Ty(), V: ArrayIndex));
206 auto *ElementPtr = B.CreateIntrinsic(ID: Intrinsic::spv_gep, Types: {Types}, Args: {Args});
207 GR->buildAssignPtr(B, ElemTy: ArrElemVecTy, Arg: ElementPtr);
208 Value *LoadVec = B.CreateLoad(Ty: ArrElemVecTy, Ptr: ElementPtr);
209 buildAssignType(B, Ty: ArrElemVecTy, Arg: LoadVec);
210 LoadedElements.push_back(Elt: makeExtractElement(B, ElementType: TargetElemTy, Vector: LoadVec,
211 Index: ElementIndexInArrayElem));
212 }
213 return buildVectorFromLoadedElements(B, TargetType, LoadedElements);
214 }
215 // Loads elements from an array and constructs a vector.
216 Value *loadVectorFromArray(IRBuilder<> &B, FixedVectorType *TargetType,
217 Value *Source) {
218 // Load each element of the array.
219 SmallVector<Value *, 4> LoadedElements;
220 SmallVector<Type *, 2> Types = {Source->getType(), Source->getType()};
221 for (unsigned I = 0; I < TargetType->getNumElements(); ++I) {
222 // Create a GEP to access the i-th element of the array.
223 SmallVector<Value *, 4> Args;
224 Args.push_back(Elt: B.getInt1(/*Inbounds=*/V: false));
225 Args.push_back(Elt: Source);
226 Args.push_back(Elt: B.getInt32(C: 0));
227 Args.push_back(Elt: ConstantInt::get(Ty: B.getInt32Ty(), V: I));
228 auto *ElementPtr = B.CreateIntrinsic(ID: Intrinsic::spv_gep, Types: {Types}, Args: {Args});
229 GR->buildAssignPtr(B, ElemTy: TargetType->getElementType(), Arg: ElementPtr);
230
231 // Load the value from the element pointer.
232 Value *Load = B.CreateLoad(Ty: TargetType->getElementType(), Ptr: ElementPtr);
233 buildAssignType(B, Ty: TargetType->getElementType(), Arg: Load);
234 LoadedElements.push_back(Elt: Load);
235 }
236 return buildVectorFromLoadedElements(B, TargetType, LoadedElements);
237 }
238
239 // Stores elements from a vector into an array.
240 void storeArrayFromVector(IRBuilder<> &B, Value *SrcVector,
241 Value *DstArrayPtr, ArrayType *ArrTy,
242 Align Alignment) {
243 auto *VecTy = cast<FixedVectorType>(Val: SrcVector->getType());
244
245 // Ensure the element types of the array and vector are the same.
246 assert(VecTy->getElementType() == ArrTy->getElementType() &&
247 "Element types of array and vector must be the same.");
248
249 const DataLayout &DL = B.GetInsertBlock()->getModule()->getDataLayout();
250 uint64_t ElemSize = DL.getTypeAllocSize(Ty: ArrTy->getElementType());
251
252 for (unsigned i = 0; i < VecTy->getNumElements(); ++i) {
253 // Create a GEP to access the i-th element of the array.
254 SmallVector<Type *, 2> Types = {DstArrayPtr->getType(),
255 DstArrayPtr->getType()};
256 SmallVector<Value *, 4> Args;
257 Args.push_back(Elt: B.getInt1(V: false));
258 Args.push_back(Elt: DstArrayPtr);
259 Args.push_back(Elt: B.getInt32(C: 0));
260 Args.push_back(Elt: ConstantInt::get(Ty: B.getInt32Ty(), V: i));
261 auto *ElementPtr = B.CreateIntrinsic(ID: Intrinsic::spv_gep, Types: {Types}, Args: {Args});
262 GR->buildAssignPtr(B, ElemTy: ArrTy->getElementType(), Arg: ElementPtr);
263
264 // Extract the element from the vector and store it.
265 Value *Index = B.getInt32(C: i);
266 SmallVector<Type *, 3> EltTypes = {VecTy->getElementType(), VecTy,
267 Index->getType()};
268 SmallVector<Value *, 2> EltArgs = {SrcVector, Index};
269 Value *Element =
270 B.CreateIntrinsic(ID: Intrinsic::spv_extractelt, Types: {EltTypes}, Args: {EltArgs});
271 buildAssignType(B, Ty: VecTy->getElementType(), Arg: Element);
272
273 Types = {Element->getType(), ElementPtr->getType()};
274 Align NewAlign = commonAlignment(A: Alignment, Offset: i * ElemSize);
275 Args = {Element, ElementPtr, B.getInt16(C: 2), B.getInt32(C: NewAlign.value())};
276 B.CreateIntrinsic(ID: Intrinsic::spv_store, Types: {Types}, Args: {Args});
277 }
278 }
279
280 // Replaces the load instruction to get rid of the ptrcast used as source
281 // operand.
282 void transformLoad(IRBuilder<> &B, LoadInst *LI, Value *CastedOperand,
283 Value *OriginalOperand) {
284 Type *FromTy = GR->findDeducedElementType(Val: OriginalOperand);
285 Type *ToTy = GR->findDeducedElementType(Val: CastedOperand);
286 Value *Output = nullptr;
287
288 auto *SAT = dyn_cast<ArrayType>(Val: FromTy);
289 auto *SVT = dyn_cast<FixedVectorType>(Val: FromTy);
290 auto *DVT = dyn_cast<FixedVectorType>(Val: ToTy);
291 auto *MAT =
292 SAT ? dyn_cast<FixedVectorType>(Val: SAT->getElementType()) : nullptr;
293
294 B.SetInsertPoint(LI);
295
296 // Destination is the element type of some member of FromTy. For example,
297 // loading the 1st element of an array:
298 // - float a = array[0];
299 if (isTypeFirstElementAggregate(Search: ToTy, Aggregate: FromTy))
300 Output = loadFirstValueFromAggregate(B, ElementType: ToTy, Source: OriginalOperand, BadLoad: LI);
301 // Destination is a smaller vector than source or different vector type.
302 // - float3 v3 = vector4;
303 // - float4 v2 = int4;
304 else if (SVT && DVT)
305 Output = loadVectorFromVector(B, SourceType: SVT, TargetType: DVT, Source: OriginalOperand);
306 else if (SAT && DVT && SAT->getElementType() == DVT->getElementType())
307 Output = loadVectorFromArray(B, TargetType: DVT, Source: OriginalOperand);
308 else if (MAT && DVT && MAT->getElementType() == DVT->getElementType())
309 Output = loadVectorFromMatrixArray(B, TargetType: DVT, Source: OriginalOperand, ArrElemVecTy: MAT);
310 else
311 llvm_unreachable("Unimplemented implicit down-cast from load.");
312
313 GR->replaceAllUsesWith(Old: LI, New: Output, /* DeleteOld= */ true);
314 DeadInstructions.push_back(x: LI);
315 }
316
317 // Creates an spv_insertelt instruction (equivalent to llvm's insertelement).
318 Value *makeInsertElement(IRBuilder<> &B, Value *Vector, Value *Element,
319 unsigned Index) {
320 Type *Int32Ty = Type::getInt32Ty(C&: B.getContext());
321 SmallVector<Type *, 4> Types = {Vector->getType(), Vector->getType(),
322 Element->getType(), Int32Ty};
323 SmallVector<Value *> Args = {Vector, Element, B.getInt32(C: Index)};
324 Instruction *NewI =
325 B.CreateIntrinsic(ID: Intrinsic::spv_insertelt, Types: {Types}, Args: {Args});
326 buildAssignType(B, Ty: Vector->getType(), Arg: NewI);
327 return NewI;
328 }
329
330 // Creates an spv_extractelt instruction (equivalent to llvm's
331 // extractelement).
332 Value *makeExtractElement(IRBuilder<> &B, Type *ElementType, Value *Vector,
333 unsigned Index) {
334 Type *Int32Ty = Type::getInt32Ty(C&: B.getContext());
335 SmallVector<Type *, 3> Types = {ElementType, Vector->getType(), Int32Ty};
336 SmallVector<Value *> Args = {Vector, B.getInt32(C: Index)};
337 Instruction *NewI =
338 B.CreateIntrinsic(ID: Intrinsic::spv_extractelt, Types: {Types}, Args: {Args});
339 buildAssignType(B, Ty: ElementType, Arg: NewI);
340 return NewI;
341 }
342
343 // Stores the given Src vector operand into the Dst vector, adjusting the size
344 // if required.
345 Value *storeVectorFromVector(IRBuilder<> &B, Value *Src, Value *Dst,
346 Align Alignment) {
347 FixedVectorType *SrcType = cast<FixedVectorType>(Val: Src->getType());
348 FixedVectorType *DstType =
349 cast<FixedVectorType>(Val: GR->findDeducedElementType(Val: Dst));
350 auto dstNumElements = DstType->getNumElements();
351 auto srcNumElements = SrcType->getNumElements();
352
353 // if the element type differs, it is a bitcast.
354 if (DstType->getElementType() != SrcType->getElementType()) {
355 // Support bitcast between vectors of different sizes only if
356 // the total bitwidth is the same.
357 [[maybe_unused]] auto dstBitWidth =
358 DstType->getElementType()->getScalarSizeInBits() * dstNumElements;
359 [[maybe_unused]] auto srcBitWidth =
360 SrcType->getElementType()->getScalarSizeInBits() * srcNumElements;
361 assert(dstBitWidth == srcBitWidth &&
362 "Unsupported bitcast between vectors of different sizes.");
363
364 Src =
365 B.CreateIntrinsic(ID: Intrinsic::spv_bitcast, Types: {DstType, SrcType}, Args: {Src});
366 buildAssignType(B, Ty: DstType, Arg: Src);
367 SrcType = DstType;
368
369 StoreInst *SI = B.CreateStore(Val: Src, Ptr: Dst);
370 SI->setAlignment(Alignment);
371 return SI;
372 }
373
374 assert(DstType->getNumElements() >= SrcType->getNumElements());
375 LoadInst *LI = B.CreateLoad(Ty: DstType, Ptr: Dst);
376 LI->setAlignment(Alignment);
377 Value *OldValues = LI;
378 buildAssignType(B, Ty: OldValues->getType(), Arg: OldValues);
379 Value *NewValues = Src;
380
381 for (unsigned I = 0; I < SrcType->getNumElements(); ++I) {
382 Value *Element =
383 makeExtractElement(B, ElementType: SrcType->getElementType(), Vector: NewValues, Index: I);
384 OldValues = makeInsertElement(B, Vector: OldValues, Element, Index: I);
385 }
386
387 StoreInst *SI = B.CreateStore(Val: OldValues, Ptr: Dst);
388 SI->setAlignment(Alignment);
389 return SI;
390 }
391
392 void buildGEPIndexChain(IRBuilder<> &B, Type *Search, Type *Aggregate,
393 SmallVectorImpl<Value *> &Indices) {
394 Indices.push_back(Elt: B.getInt32(C: 0));
395
396 if (Search == Aggregate)
397 return;
398
399 if (auto *ST = dyn_cast<StructType>(Val: Aggregate))
400 buildGEPIndexChain(B, Search, Aggregate: ST->getTypeAtIndex(N: 0u), Indices);
401 else if (auto *AT = dyn_cast<ArrayType>(Val: Aggregate))
402 buildGEPIndexChain(B, Search, Aggregate: AT->getElementType(), Indices);
403 else if (auto *VT = dyn_cast<FixedVectorType>(Val: Aggregate))
404 buildGEPIndexChain(B, Search, Aggregate: VT->getElementType(), Indices);
405 else
406 llvm_unreachable("Bad access chain?");
407 }
408
409 // Stores the given Src value into the first entry of the Dst aggregate.
410 Value *storeToFirstValueAggregate(IRBuilder<> &B, Value *Src, Value *Dst,
411 Type *DstPointeeType, Align Alignment) {
412 SmallVector<Type *, 2> Types = {Dst->getType(), Dst->getType()};
413 SmallVector<Value *, 8> Args{/* isInBounds= */ B.getInt1(V: true), Dst};
414 buildGEPIndexChain(B, Search: Src->getType(), Aggregate: DstPointeeType, Indices&: Args);
415 auto *GEP = B.CreateIntrinsic(ID: Intrinsic::spv_gep, Types: {Types}, Args: {Args});
416 GR->buildAssignPtr(B, ElemTy: Src->getType(), Arg: GEP);
417 StoreInst *SI = B.CreateStore(Val: Src, Ptr: GEP);
418 SI->setAlignment(Alignment);
419 return SI;
420 }
421
422 bool isTypeFirstElementAggregate(Type *Search, Type *Aggregate) {
423 if (Search == Aggregate)
424 return true;
425 if (auto *ST = dyn_cast<StructType>(Val: Aggregate))
426 return isTypeFirstElementAggregate(Search, Aggregate: ST->getTypeAtIndex(N: 0u));
427 if (auto *VT = dyn_cast<FixedVectorType>(Val: Aggregate))
428 return isTypeFirstElementAggregate(Search, Aggregate: VT->getElementType());
429 if (auto *AT = dyn_cast<ArrayType>(Val: Aggregate))
430 return isTypeFirstElementAggregate(Search, Aggregate: AT->getElementType());
431 return false;
432 }
433
434 // Transforms a store instruction (or SPV intrinsic) using a ptrcast as
435 // operand into a valid logical SPIR-V store with no ptrcast.
436 void transformStore(IRBuilder<> &B, Instruction *BadStore, Value *Src,
437 Value *Dst, Align Alignment) {
438 Type *ToTy = GR->findDeducedElementType(Val: Dst);
439 Type *FromTy = Src->getType();
440
441 auto *S_VT = dyn_cast<FixedVectorType>(Val: FromTy);
442 auto *D_VT = dyn_cast<FixedVectorType>(Val: ToTy);
443 auto *D_AT = dyn_cast<ArrayType>(Val: ToTy);
444
445 B.SetInsertPoint(BadStore);
446 if (isTypeFirstElementAggregate(Search: FromTy, Aggregate: ToTy))
447 storeToFirstValueAggregate(B, Src, Dst, DstPointeeType: ToTy, Alignment);
448 else if (D_VT && S_VT)
449 storeVectorFromVector(B, Src, Dst, Alignment);
450 else if (D_VT && !S_VT && FromTy == D_VT->getElementType())
451 storeToFirstValueAggregate(B, Src, Dst, DstPointeeType: D_VT, Alignment);
452 else if (D_AT && S_VT && S_VT->getElementType() == D_AT->getElementType())
453 storeArrayFromVector(B, SrcVector: Src, DstArrayPtr: Dst, ArrTy: D_AT, Alignment);
454 else
455 llvm_unreachable("Unsupported ptrcast use in store. Please fix.");
456
457 DeadInstructions.push_back(x: BadStore);
458 }
459
460 void legalizePointerCast(IntrinsicInst *II) {
461 Value *CastedOperand = II;
462 Value *OriginalOperand = II->getOperand(i_nocapture: 0);
463
464 IRBuilder<> B(II->getContext());
465 std::vector<Value *> Users;
466 for (Use &U : II->uses())
467 Users.push_back(x: U.getUser());
468
469 for (Value *User : Users) {
470 if (LoadInst *LI = dyn_cast<LoadInst>(Val: User)) {
471 transformLoad(B, LI, CastedOperand, OriginalOperand);
472 continue;
473 }
474
475 if (StoreInst *SI = dyn_cast<StoreInst>(Val: User)) {
476 transformStore(B, BadStore: SI, Src: SI->getValueOperand(), Dst: OriginalOperand,
477 Alignment: SI->getAlign());
478 continue;
479 }
480
481 if (IntrinsicInst *Intrin = dyn_cast<IntrinsicInst>(Val: User)) {
482 if (Intrin->getIntrinsicID() == Intrinsic::spv_assign_ptr_type) {
483 DeadInstructions.push_back(x: Intrin);
484 continue;
485 }
486
487 if (Intrin->getIntrinsicID() == Intrinsic::spv_gep) {
488 GR->replaceAllUsesWith(Old: CastedOperand, New: OriginalOperand,
489 /* DeleteOld= */ false);
490 continue;
491 }
492
493 if (Intrin->getIntrinsicID() == Intrinsic::spv_store) {
494 Align Alignment;
495 if (ConstantInt *C = dyn_cast<ConstantInt>(Val: Intrin->getOperand(i_nocapture: 3)))
496 Alignment = Align(C->getZExtValue());
497 transformStore(B, BadStore: Intrin, Src: Intrin->getArgOperand(i: 0), Dst: OriginalOperand,
498 Alignment);
499 continue;
500 }
501 }
502
503 llvm_unreachable("Unsupported ptrcast user. Please fix.");
504 }
505
506 DeadInstructions.push_back(x: II);
507 }
508
509public:
510 SPIRVLegalizePointerCast(SPIRVTargetMachine *TM) : FunctionPass(ID), TM(TM) {}
511
512 bool runOnFunction(Function &F) override {
513 const SPIRVSubtarget &ST = TM->getSubtarget<SPIRVSubtarget>(F);
514 GR = ST.getSPIRVGlobalRegistry();
515 DeadInstructions.clear();
516
517 std::vector<IntrinsicInst *> WorkList;
518 for (auto &BB : F) {
519 for (auto &I : BB) {
520 auto *II = dyn_cast<IntrinsicInst>(Val: &I);
521 if (II && II->getIntrinsicID() == Intrinsic::spv_ptrcast)
522 WorkList.push_back(x: II);
523 }
524 }
525
526 for (IntrinsicInst *II : WorkList)
527 legalizePointerCast(II);
528
529 for (Instruction *I : DeadInstructions)
530 I->eraseFromParent();
531
532 return DeadInstructions.size() != 0;
533 }
534
535private:
536 SPIRVTargetMachine *TM = nullptr;
537 SPIRVGlobalRegistry *GR = nullptr;
538 std::vector<Instruction *> DeadInstructions;
539
540public:
541 static char ID;
542};
543} // namespace
544
545char SPIRVLegalizePointerCast::ID = 0;
546INITIALIZE_PASS(SPIRVLegalizePointerCast, "spirv-legalize-bitcast",
547 "SPIRV legalize bitcast pass", false, false)
548
549FunctionPass *llvm::createSPIRVLegalizePointerCastPass(SPIRVTargetMachine *TM) {
550 return new SPIRVLegalizePointerCast(TM);
551}
552