53#include "llvm/IR/IntrinsicsSPIRV.h"
60class SPIRVLegalizePointerCastImpl {
67 {Arg->
getType()}, OfType, Arg, {},
B);
68 GR->addAssignPtrTypeInstr(Arg, AssignCI);
71 static FixedVectorType *makeVectorFromTotalBits(
Type *ElemTy,
74 assert(ElemBits && TotalBits % ElemBits == 0 &&
75 "TotalBits must be divisible by element bit size");
80 FixedVectorType *DstTy) {
83 "shuffle resize expects identical element types");
86 const unsigned NumSource = SrcTy->getNumElements();
88 SmallVector<int>
Mask(NumNeeded);
89 for (
unsigned I = 0;
I < NumNeeded; ++
I)
90 Mask[
I] = (
I < NumSource) ?
static_cast<int>(
I) : -1;
92 Value *Resized =
B.CreateShuffleVector(V, V, Mask);
93 buildAssignType(
B, DstTy, Resized);
102 FixedVectorType *TargetType,
Value *Source) {
103 LoadInst *NewLoad =
B.CreateLoad(SourceType, Source);
104 buildAssignType(
B, SourceType, NewLoad);
105 Value *AssignValue = NewLoad;
107 const DataLayout &
DL =
B.GetInsertBlock()->getModule()->getDataLayout();
108 TypeSize TargetTypeSize =
DL.getTypeSizeInBits(TargetType);
109 TypeSize SourceTypeSize =
DL.getTypeSizeInBits(SourceType);
111 Value *BitcastSrcVal = NewLoad;
112 FixedVectorType *BitcastSrcTy =
114 FixedVectorType *BitcastDstTy = TargetType;
116 if (TargetTypeSize != SourceTypeSize) {
117 unsigned TargetElemBits =
119 if (SourceTypeSize % TargetElemBits == 0) {
122 BitcastDstTy = makeVectorFromTotalBits(TargetType->
getElementType(),
126 BitcastSrcTy = makeVectorFromTotalBits(SourceType->
getElementType(),
128 BitcastSrcVal = resizeVectorBitsWithShuffle(
B, NewLoad, BitcastSrcTy);
132 B.CreateIntrinsic(Intrinsic::spv_bitcast,
133 {BitcastDstTy, BitcastSrcTy}, {BitcastSrcVal});
134 buildAssignType(
B, BitcastDstTy, AssignValue);
135 if (BitcastDstTy == TargetType)
143 Value *Output =
B.CreateShuffleVector(AssignValue, AssignValue, Mask);
144 buildAssignType(
B, TargetType, Output);
150 bool isCompatibleMemoryLayout(
Type *ToTy,
Type *FromTy) {
159 if (
SAT->getElementType() == DVT->getElementType())
162 if (MAT->getElementType() == DVT->getElementType())
170 std::optional<std::pair<Value *, Type *>>
172 Type *PointerType,
Type *TargetElemType,
174 Type *CurrentTy = GR->findDeducedElementType(BasePtr);
175 assert(CurrentTy &&
"Could not deduce aggregate type");
176 SmallVector<Value *, 8>
Args{
B.getInt1(IsInBounds),
178 Args.push_back(
B.getInt32(0));
180 while (!isCompatibleMemoryLayout(TargetElemType, CurrentTy)) {
182 if (
ST->getNumElements() == 0)
184 CurrentTy =
ST->getTypeAtIndex(0u);
186 CurrentTy = AT->getElementType();
188 CurrentTy = VT->getElementType();
192 Args.push_back(
B.getInt32(0));
196 if (
Args.size() > 3) {
198 GEP =
B.CreateIntrinsic(Intrinsic::spv_gep, {
Types}, {
Args});
199 GR->buildAssignPtr(
B, CurrentTy,
GEP);
202 return std::make_pair(
GEP, CurrentTy);
210 auto ResultOpt = getPointerToFirstCompatibleType(
212 assert(ResultOpt &&
"Failed to load from aggregate: "
213 "Could not find compatible memory layout.");
214 auto [
GEP, CurrentTy] = *ResultOpt;
222 if (ElementType == CurrentTy) {
223 LoadInst *LI =
B.CreateLoad(ElementType,
GEP);
225 buildAssignType(
B, ElementType, LI);
229 return loadVectorFromVector(
B, SVT, DVT,
GEP);
230 if (
SAT && DVT &&
SAT->getElementType() == DVT->getElementType())
231 return loadVectorFromArray(
B, DVT,
GEP);
232 if (MAT && DVT && MAT->getElementType() == DVT->getElementType())
233 return loadVectorFromMatrixArray(
B, DVT,
GEP, MAT);
238 buildVectorFromLoadedElements(
IRBuilder<> &
B, FixedVectorType *TargetType,
239 SmallVector<Value *, 4> &LoadedElements) {
242 buildAssignType(
B, TargetType, NewVector);
250 NewVector =
B.CreateIntrinsic(Intrinsic::spv_insertelt, {
Types}, {
Args});
251 buildAssignType(
B, TargetType, NewVector);
260 FixedVectorType *ArrElemVecTy) {
264 SmallVector<Value *, 4> LoadedElements;
267 unsigned ArrayIndex =
I / ScalarsPerArrayElement;
268 unsigned ElementIndexInArrayElem =
I % ScalarsPerArrayElement;
270 std::array<Value *, 4>
Args = {
271 B.getInt1(
false),
Source,
B.getInt32(0),
272 ConstantInt::get(
B.getInt32Ty(), ArrayIndex)};
273 auto *ElementPtr =
B.CreateIntrinsic(Intrinsic::spv_gep, {
Types}, {
Args});
274 GR->buildAssignPtr(
B, ArrElemVecTy, ElementPtr);
275 Value *LoadVec =
B.CreateLoad(ArrElemVecTy, ElementPtr);
276 buildAssignType(
B, ArrElemVecTy, LoadVec);
277 LoadedElements.
push_back(makeExtractElement(
B, TargetElemTy, LoadVec,
278 ElementIndexInArrayElem));
280 return buildVectorFromLoadedElements(
B, TargetType, LoadedElements);
286 SmallVector<Value *, 4> LoadedElements;
290 std::array<Value *, 4>
Args = {
B.getInt1(
false),
Source,
292 ConstantInt::get(
B.getInt32Ty(),
I)};
293 auto *ElementPtr =
B.CreateIntrinsic(Intrinsic::spv_gep, {
Types}, {
Args});
301 return buildVectorFromLoadedElements(
B, TargetType, LoadedElements);
306 Value *DstArrayPtr, ArrayType *ArrTy,
312 unsigned SrcNumElements = SrcVecTy->getNumElements();
314 SrcNumElements % ScalarsPerArrayElement == 0 &&
315 "Source vector size must be a multiple of array element vector size");
320 for (
unsigned I = 0;
I < SrcNumElements;
I += ScalarsPerArrayElement) {
321 unsigned ArrayIndex =
I / ScalarsPerArrayElement;
323 std::array<Value *, 4>
Args = {
324 B.getInt1(
false), DstArrayPtr,
B.getInt32(0),
325 ConstantInt::get(
B.getInt32Ty(), ArrayIndex)};
326 auto *ElementPtr =
B.CreateIntrinsic(Intrinsic::spv_gep, {
Types}, {
Args});
327 GR->buildAssignPtr(
B, ArrElemVecTy, ElementPtr);
331 for (
unsigned J = 0; J < ScalarsPerArrayElement; ++J)
332 Elements.push_back(makeExtractElement(
B, ElemTy, SrcVector,
I + J));
335 Value *Vec = buildVectorFromLoadedElements(
B, ArrElemVecTy, Elements);
336 StoreInst *
SI =
B.CreateStore(Vec, ElementPtr);
337 SI->setAlignment(Alignment);
343 Value *DstArrayPtr, ArrayType *ArrTy,
346 Type *ElemTy = ArrTy->getElementType();
349 assert(VecTy->getElementType() == ElemTy &&
350 "Element types of array and vector must be the same.");
354 for (
unsigned I = 0,
E = VecTy->getNumElements();
I <
E; ++
I) {
356 std::array<Value *, 4>
Args = {
B.getInt1(
false), DstArrayPtr,
358 ConstantInt::get(
B.getInt32Ty(),
I)};
359 auto *ElementPtr =
B.CreateIntrinsic(Intrinsic::spv_gep, {
Types}, {
Args});
360 GR->buildAssignPtr(
B, ElemTy, ElementPtr);
363 Value *Element = makeExtractElement(
B, ElemTy, SrcVector,
I);
364 StoreInst *
SI =
B.CreateStore(Element, ElementPtr);
365 SI->setAlignment(Alignment);
372 Value *OriginalOperand) {
373 Type *ToTy = GR->findDeducedElementType(CastedOperand);
374 B.SetInsertPoint(LI);
376 Value *Output = buildLegalizedLoad(
B, ToTy, OriginalOperand, LI);
378 GR->replaceAllUsesWith(LI, Output,
true);
379 DeadInstructions.push_back(LI);
390 B.CreateIntrinsic(Intrinsic::spv_insertelt, {
Types}, {
Args});
391 buildAssignType(
B,
Vector->getType(), NewI);
403 B.CreateIntrinsic(Intrinsic::spv_extractelt, {
Types}, {
Args});
404 buildAssignType(
B, ElementType, NewI);
413 FixedVectorType *DstType =
422 [[maybe_unused]]
auto dstBitWidth =
424 [[maybe_unused]]
auto srcBitWidth =
426 assert(dstBitWidth == srcBitWidth &&
427 "Unsupported bitcast between vectors of different sizes.");
430 B.CreateIntrinsic(Intrinsic::spv_bitcast, {DstType, SrcType}, {Src});
431 buildAssignType(
B, DstType, Src);
434 StoreInst *
SI =
B.CreateStore(Src, Dst);
435 SI->setAlignment(Alignment);
440 LoadInst *LI =
B.CreateLoad(DstType, Dst);
442 Value *OldValues = LI;
443 buildAssignType(
B, OldValues->
getType(), OldValues);
444 Value *NewValues = Src;
449 OldValues = makeInsertElement(
B, OldValues, Element,
I);
452 StoreInst *
SI =
B.CreateStore(OldValues, Dst);
453 SI->setAlignment(Alignment);
461 auto ResultOpt = getPointerToFirstCompatibleType(
B, Dst, Dst->getType(),
462 Src->getType(),
true);
463 assert(ResultOpt &&
"Failed to store to aggregate: "
464 "Could not find compatible memory layout.");
465 auto [
GEP, CurrentTy] = *ResultOpt;
473 if (Src->getType() == CurrentTy) {
474 StoreInst *
SI =
B.CreateStore(Src,
GEP);
475 SI->setAlignment(Alignment);
479 storeVectorFromVector(
B, Src,
GEP, Alignment);
482 if (DAT && SVT && SVT->getElementType() == DAT->getElementType()) {
483 storeArrayFromVector(
B, Src,
GEP, DAT, Alignment);
486 if (DMAT && SVT && DMAT->getElementType() == SVT->getElementType()) {
487 storeMatrixArrayFromVector(
B, Src,
GEP, DAT, Alignment);
497 Value *Dst, Align Alignment) {
498 B.SetInsertPoint(BadStore);
499 buildLegalizedStore(
B, Src, Dst, Alignment);
500 DeadInstructions.push_back(BadStore);
503 void legalizePointerCast(IntrinsicInst *
II) {
505 Value *OriginalOperand =
II->getOperand(0);
508 std::vector<Value *>
Users;
509 for (Use &U :
II->uses())
510 Users.push_back(
U.getUser());
514 transformLoad(
B, LI, CastedOperand, OriginalOperand);
519 transformStore(
B, SI,
SI->getValueOperand(), OriginalOperand,
525 if (Intrin->getIntrinsicID() == Intrinsic::spv_assign_ptr_type) {
526 DeadInstructions.push_back(Intrin);
530 if (Intrin->getIntrinsicID() == Intrinsic::spv_gep) {
531 GR->replaceAllUsesWith(CastedOperand, OriginalOperand,
536 if (Intrin->getIntrinsicID() == Intrinsic::spv_store) {
539 Alignment =
Align(
C->getZExtValue());
540 transformStore(
B, Intrin, Intrin->getArgOperand(0), OriginalOperand,
549 DeadInstructions.push_back(
II);
553 SPIRVLegalizePointerCastImpl(
const SPIRVTargetMachine &TM) : TM(TM) {}
555 bool run(Function &
F) {
556 const SPIRVSubtarget &
ST = TM.getSubtarget<SPIRVSubtarget>(
F);
557 GR =
ST.getSPIRVGlobalRegistry();
558 DeadInstructions.clear();
560 std::vector<IntrinsicInst *> WorkList;
564 if (
II &&
II->getIntrinsicID() == Intrinsic::spv_ptrcast)
565 WorkList.push_back(
II);
569 for (IntrinsicInst *
II : WorkList)
570 legalizePointerCast(
II);
572 for (Instruction *
I : DeadInstructions)
573 I->eraseFromParent();
575 return DeadInstructions.size() != 0;
579 const SPIRVTargetMachine &TM;
580 SPIRVGlobalRegistry *GR =
nullptr;
581 std::vector<Instruction *> DeadInstructions;
584class SPIRVLegalizePointerCastLegacy :
public FunctionPass {
587 SPIRVLegalizePointerCastLegacy(
const SPIRVTargetMachine &TM)
588 : FunctionPass(ID), TM(TM) {}
591 return SPIRVLegalizePointerCastImpl(TM).run(
F);
595 const SPIRVTargetMachine &TM;
605char SPIRVLegalizePointerCastLegacy::ID = 0;
607 "SPIRV legalize pointer cast pass",
false,
false)
610 return new SPIRVLegalizePointerCastLegacy(*TM);
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)
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.
A set of analyses that are preserved following a run of a transformation pass.
static PreservedAnalyses none()
Convenience factory function for the empty preserved set.
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
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.
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.
DXILDebugInfoMap run(Module &M)
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.
AnalysisManager< Function > FunctionAnalysisManager
Convenience typedef for the Function analysis manager.
FunctionPass * createSPIRVLegalizePointerCastPass(SPIRVTargetMachine *TM)