52#include "llvm/IR/IntrinsicsSPIRV.h"
66 {Arg->
getType()}, OfType, Arg, {},
B);
67 GR->addAssignPtrTypeInstr(Arg, AssignCI);
70 static FixedVectorType *makeVectorFromTotalBits(
Type *ElemTy,
73 assert(ElemBits && TotalBits % ElemBits == 0 &&
74 "TotalBits must be divisible by element bit size");
79 FixedVectorType *DstTy) {
82 "shuffle resize expects identical element types");
85 const unsigned NumSource = SrcTy->getNumElements();
87 SmallVector<int>
Mask(NumNeeded);
88 for (
unsigned I = 0;
I < NumNeeded; ++
I)
89 Mask[
I] = (
I < NumSource) ?
static_cast<int>(
I) : -1;
91 Value *Resized =
B.CreateShuffleVector(V, V, Mask);
92 buildAssignType(
B, DstTy, Resized);
101 FixedVectorType *TargetType,
Value *Source) {
102 LoadInst *NewLoad =
B.CreateLoad(SourceType, Source);
103 buildAssignType(
B, SourceType, NewLoad);
104 Value *AssignValue = NewLoad;
106 const DataLayout &
DL =
B.GetInsertBlock()->getModule()->getDataLayout();
107 TypeSize TargetTypeSize =
DL.getTypeSizeInBits(TargetType);
108 TypeSize SourceTypeSize =
DL.getTypeSizeInBits(SourceType);
110 Value *BitcastSrcVal = NewLoad;
111 FixedVectorType *BitcastSrcTy =
113 FixedVectorType *BitcastDstTy = TargetType;
115 if (TargetTypeSize != SourceTypeSize) {
116 unsigned TargetElemBits =
118 if (SourceTypeSize % TargetElemBits == 0) {
121 BitcastDstTy = makeVectorFromTotalBits(TargetType->
getElementType(),
125 BitcastSrcTy = makeVectorFromTotalBits(SourceType->
getElementType(),
127 BitcastSrcVal = resizeVectorBitsWithShuffle(
B, NewLoad, BitcastSrcTy);
131 B.CreateIntrinsic(Intrinsic::spv_bitcast,
132 {BitcastDstTy, BitcastSrcTy}, {BitcastSrcVal});
133 buildAssignType(
B, BitcastDstTy, AssignValue);
134 if (BitcastDstTy == TargetType)
142 Value *Output =
B.CreateShuffleVector(AssignValue, AssignValue, Mask);
143 buildAssignType(
B, TargetType, Output);
151 Value *Source, LoadInst *BadLoad) {
154 SmallVector<Value *, 8>
Args{
B.getInt1(
false),
Source};
156 Type *AggregateType = GR->findDeducedElementType(Source);
157 assert(AggregateType &&
"Could not deduce aggregate type");
158 buildGEPIndexChain(
B, ElementType, AggregateType, Args);
160 auto *
GEP =
B.CreateIntrinsic(Intrinsic::spv_gep, {
Types}, {
Args});
161 GR->buildAssignPtr(
B, ElementType,
GEP);
163 LoadInst *LI =
B.CreateLoad(ElementType,
GEP);
165 buildAssignType(
B, ElementType, LI);
169 buildVectorFromLoadedElements(
IRBuilder<> &
B, FixedVectorType *TargetType,
170 SmallVector<Value *, 4> &LoadedElements) {
173 buildAssignType(
B, TargetType, NewVector);
181 NewVector =
B.CreateIntrinsic(Intrinsic::spv_insertelt, {
Types}, {
Args});
182 buildAssignType(
B, TargetType, NewVector);
191 FixedVectorType *ArrElemVecTy) {
195 SmallVector<Value *, 4> LoadedElements;
198 unsigned ArrayIndex =
I / ScalarsPerArrayElement;
199 unsigned ElementIndexInArrayElem =
I % ScalarsPerArrayElement;
201 SmallVector<Value *, 4>
Args;
202 Args.push_back(
B.getInt1(
false));
203 Args.push_back(Source);
204 Args.push_back(
B.getInt32(0));
205 Args.push_back(ConstantInt::get(
B.getInt32Ty(), ArrayIndex));
206 auto *ElementPtr =
B.CreateIntrinsic(Intrinsic::spv_gep, {
Types}, {
Args});
207 GR->buildAssignPtr(
B, ArrElemVecTy, ElementPtr);
208 Value *LoadVec =
B.CreateLoad(ArrElemVecTy, ElementPtr);
209 buildAssignType(
B, ArrElemVecTy, LoadVec);
210 LoadedElements.
push_back(makeExtractElement(
B, TargetElemTy, LoadVec,
211 ElementIndexInArrayElem));
213 return buildVectorFromLoadedElements(
B, TargetType, LoadedElements);
219 SmallVector<Value *, 4> LoadedElements;
223 SmallVector<Value *, 4>
Args;
224 Args.push_back(
B.getInt1(
false));
225 Args.push_back(Source);
226 Args.push_back(
B.getInt32(0));
227 Args.push_back(ConstantInt::get(
B.getInt32Ty(),
I));
228 auto *ElementPtr =
B.CreateIntrinsic(Intrinsic::spv_gep, {
Types}, {
Args});
236 return buildVectorFromLoadedElements(
B, TargetType, LoadedElements);
241 Value *DstArrayPtr, ArrayType *ArrTy,
246 assert(VecTy->getElementType() == ArrTy->getElementType() &&
247 "Element types of array and vector must be the same.");
249 const DataLayout &
DL =
B.GetInsertBlock()->getModule()->getDataLayout();
250 uint64_t ElemSize =
DL.getTypeAllocSize(ArrTy->getElementType());
252 for (
unsigned i = 0; i < VecTy->getNumElements(); ++i) {
256 SmallVector<Value *, 4>
Args;
257 Args.push_back(
B.getInt1(
false));
258 Args.push_back(DstArrayPtr);
259 Args.push_back(
B.getInt32(0));
260 Args.push_back(ConstantInt::get(
B.getInt32Ty(), i));
261 auto *ElementPtr =
B.CreateIntrinsic(Intrinsic::spv_gep, {
Types}, {
Args});
262 GR->buildAssignPtr(
B, ArrTy->getElementType(), ElementPtr);
268 SmallVector<Value *, 2> EltArgs = {SrcVector,
Index};
270 B.CreateIntrinsic(Intrinsic::spv_extractelt, {EltTypes}, {EltArgs});
271 buildAssignType(
B, VecTy->getElementType(), Element);
275 Args = {Element, ElementPtr,
B.getInt16(2),
B.getInt32(NewAlign.
value())};
276 B.CreateIntrinsic(Intrinsic::spv_store, {
Types}, {
Args});
283 Value *OriginalOperand) {
284 Type *FromTy = GR->findDeducedElementType(OriginalOperand);
285 Type *ToTy = GR->findDeducedElementType(CastedOperand);
286 Value *Output =
nullptr;
294 B.SetInsertPoint(LI);
299 if (isTypeFirstElementAggregate(ToTy, FromTy))
300 Output = loadFirstValueFromAggregate(
B, ToTy, OriginalOperand, LI);
305 Output = loadVectorFromVector(
B, SVT, DVT, OriginalOperand);
306 else if (
SAT && DVT &&
SAT->getElementType() == DVT->getElementType())
307 Output = loadVectorFromArray(
B, DVT, OriginalOperand);
308 else if (MAT && DVT && MAT->getElementType() == DVT->getElementType())
309 Output = loadVectorFromMatrixArray(
B, DVT, OriginalOperand, MAT);
313 GR->replaceAllUsesWith(LI, Output,
true);
314 DeadInstructions.push_back(LI);
325 B.CreateIntrinsic(Intrinsic::spv_insertelt, {
Types}, {
Args});
326 buildAssignType(
B,
Vector->getType(), NewI);
338 B.CreateIntrinsic(Intrinsic::spv_extractelt, {
Types}, {
Args});
339 buildAssignType(
B, ElementType, NewI);
348 FixedVectorType *DstType =
357 [[maybe_unused]]
auto dstBitWidth =
359 [[maybe_unused]]
auto srcBitWidth =
361 assert(dstBitWidth == srcBitWidth &&
362 "Unsupported bitcast between vectors of different sizes.");
365 B.CreateIntrinsic(Intrinsic::spv_bitcast, {DstType, SrcType}, {Src});
366 buildAssignType(
B, DstType, Src);
369 StoreInst *
SI =
B.CreateStore(Src, Dst);
370 SI->setAlignment(Alignment);
375 LoadInst *LI =
B.CreateLoad(DstType, Dst);
377 Value *OldValues = LI;
378 buildAssignType(
B, OldValues->
getType(), OldValues);
379 Value *NewValues = Src;
384 OldValues = makeInsertElement(
B, OldValues, Element,
I);
387 StoreInst *
SI =
B.CreateStore(OldValues, Dst);
388 SI->setAlignment(Alignment);
393 SmallVectorImpl<Value *> &Indices) {
396 if (Search == Aggregate)
400 buildGEPIndexChain(
B, Search,
ST->getTypeAtIndex(0u), Indices);
402 buildGEPIndexChain(
B, Search, AT->getElementType(), Indices);
404 buildGEPIndexChain(
B, Search, VT->getElementType(), Indices);
411 Type *DstPointeeType, Align Alignment) {
413 SmallVector<Value *, 8>
Args{
B.getInt1(
true), Dst};
414 buildGEPIndexChain(
B, Src->getType(), DstPointeeType, Args);
415 auto *
GEP =
B.CreateIntrinsic(Intrinsic::spv_gep, {
Types}, {
Args});
416 GR->buildAssignPtr(
B, Src->getType(),
GEP);
417 StoreInst *
SI =
B.CreateStore(Src,
GEP);
418 SI->setAlignment(Alignment);
422 bool isTypeFirstElementAggregate(
Type *Search,
Type *Aggregate) {
423 if (Search == Aggregate)
426 return isTypeFirstElementAggregate(Search,
ST->getTypeAtIndex(0u));
428 return isTypeFirstElementAggregate(Search, VT->getElementType());
430 return isTypeFirstElementAggregate(Search, AT->getElementType());
437 Value *Dst, Align Alignment) {
438 Type *ToTy = GR->findDeducedElementType(Dst);
439 Type *FromTy = Src->getType();
445 B.SetInsertPoint(BadStore);
446 if (isTypeFirstElementAggregate(FromTy, ToTy))
447 storeToFirstValueAggregate(
B, Src, Dst, 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, D_VT, Alignment);
452 else if (D_AT && S_VT && S_VT->getElementType() == D_AT->getElementType())
453 storeArrayFromVector(
B, Src, Dst, D_AT, Alignment);
457 DeadInstructions.push_back(BadStore);
460 void legalizePointerCast(IntrinsicInst *
II) {
462 Value *OriginalOperand =
II->getOperand(0);
465 std::vector<Value *>
Users;
466 for (Use &U :
II->uses())
467 Users.push_back(
U.getUser());
471 transformLoad(
B, LI, CastedOperand, OriginalOperand);
476 transformStore(
B, SI,
SI->getValueOperand(), OriginalOperand,
482 if (Intrin->getIntrinsicID() == Intrinsic::spv_assign_ptr_type) {
483 DeadInstructions.push_back(Intrin);
487 if (Intrin->getIntrinsicID() == Intrinsic::spv_gep) {
488 GR->replaceAllUsesWith(CastedOperand, OriginalOperand,
493 if (Intrin->getIntrinsicID() == Intrinsic::spv_store) {
496 Alignment =
Align(
C->getZExtValue());
497 transformStore(
B, Intrin, Intrin->getArgOperand(0), OriginalOperand,
506 DeadInstructions.push_back(
II);
510 SPIRVLegalizePointerCast(SPIRVTargetMachine *TM) : FunctionPass(ID), TM(TM) {}
513 const SPIRVSubtarget &
ST = TM->getSubtarget<SPIRVSubtarget>(
F);
514 GR =
ST.getSPIRVGlobalRegistry();
515 DeadInstructions.clear();
517 std::vector<IntrinsicInst *> WorkList;
521 if (
II &&
II->getIntrinsicID() == Intrinsic::spv_ptrcast)
522 WorkList.push_back(
II);
526 for (IntrinsicInst *
II : WorkList)
527 legalizePointerCast(
II);
529 for (Instruction *
I : DeadInstructions)
530 I->eraseFromParent();
532 return DeadInstructions.size() != 0;
536 SPIRVTargetMachine *TM =
nullptr;
537 SPIRVGlobalRegistry *GR =
nullptr;
538 std::vector<Instruction *> DeadInstructions;
545char SPIRVLegalizePointerCast::ID = 0;
547 "SPIRV legalize bitcast pass",
false,
false)
550 return new SPIRVLegalizePointerCast(TM);
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static bool runOnFunction(Function &F, bool PostInlining)
iv Induction Variable Users
uint64_t IntrinsicInst * II
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
unsigned getNumElements() const
static LLVM_ABI FixedVectorType * get(Type *ElementType, unsigned NumElts)
FunctionPass class - This class is used to implement most global optimizations.
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.
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.
Type * getType() const
All values are typed, get the type of this value.
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.
ElementType
The element type of an SRV or UAV resource.
friend class Instruction
Iterator for Instructions in a `BasicBlock.
This is an optimization pass for GlobalISel generic memory operations.
FunctionAddr VTableAddr Value
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
FunctionAddr VTableAddr uintptr_t uintptr_t Int32Ty
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.
Align commonAlignment(Align A, uint64_t Offset)
Returns the alignment that satisfies both alignments.
FunctionPass * createSPIRVLegalizePointerCastPass(SPIRVTargetMachine *TM)
constexpr uint64_t value() const
This is a hole in the type system and should not be abused.