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 Align OriginalAlign) {
104 LoadInst *NewLoad =
B.CreateLoad(SourceType, Source);
106 buildAssignType(
B, SourceType, NewLoad);
107 Value *AssignValue = NewLoad;
109 const DataLayout &
DL =
B.GetInsertBlock()->getModule()->getDataLayout();
110 TypeSize TargetTypeSize =
DL.getTypeSizeInBits(TargetType);
111 TypeSize SourceTypeSize =
DL.getTypeSizeInBits(SourceType);
113 Value *BitcastSrcVal = NewLoad;
114 FixedVectorType *BitcastSrcTy =
116 FixedVectorType *BitcastDstTy = TargetType;
118 if (TargetTypeSize != SourceTypeSize) {
119 unsigned TargetElemBits =
121 if (SourceTypeSize % TargetElemBits == 0) {
124 BitcastDstTy = makeVectorFromTotalBits(TargetType->
getElementType(),
128 BitcastSrcTy = makeVectorFromTotalBits(SourceType->
getElementType(),
130 BitcastSrcVal = resizeVectorBitsWithShuffle(
B, NewLoad, BitcastSrcTy);
134 B.CreateIntrinsic(Intrinsic::spv_bitcast,
135 {BitcastDstTy, BitcastSrcTy}, {BitcastSrcVal});
136 buildAssignType(
B, BitcastDstTy, AssignValue);
137 if (BitcastDstTy == TargetType)
143 const unsigned NumSource = AssignVecTy->getNumElements();
149 if (NumTarget > NumSource) {
151 buildAssignType(
B, TargetType, Result);
152 for (
unsigned I = 0;
I < NumSource; ++
I) {
154 Result = makeInsertElement(
B, Result, Scalar,
I);
159 assert(NumTarget < NumSource);
160 SmallVector<int>
Mask( NumTarget);
161 for (
unsigned I = 0;
I < NumTarget; ++
I)
163 Value *Output =
B.CreateShuffleVector(AssignValue, AssignValue, Mask);
164 buildAssignType(
B, TargetType, Output);
170 bool isCompatibleMemoryLayout(
Type *ToTy,
Type *FromTy) {
179 if (
SAT->getElementType() == DVT->getElementType())
182 if (MAT->getElementType() == DVT->getElementType())
190 std::optional<std::pair<Value *, Type *>>
192 Type *PointerType,
Type *TargetElemType,
194 Type *CurrentTy = GR->findDeducedElementType(BasePtr);
195 assert(CurrentTy &&
"Could not deduce aggregate type");
196 SmallVector<Value *, 8>
Args{
B.getInt1(IsInBounds),
198 Args.push_back(
B.getInt32(0));
200 while (!isCompatibleMemoryLayout(TargetElemType, CurrentTy)) {
202 if (
ST->getNumElements() == 0)
204 CurrentTy =
ST->getTypeAtIndex(0u);
206 CurrentTy = AT->getElementType();
208 CurrentTy = VT->getElementType();
212 Args.push_back(
B.getInt32(0));
216 if (
Args.size() > 3) {
218 GEP =
B.CreateIntrinsic(Intrinsic::spv_gep, {
Types}, {
Args});
219 GR->buildAssignPtr(
B, CurrentTy,
GEP);
222 return std::make_pair(
GEP, CurrentTy);
230 auto ResultOpt = getPointerToFirstCompatibleType(
232 assert(ResultOpt &&
"Failed to load from aggregate: "
233 "Could not find compatible memory layout.");
234 auto [
GEP, CurrentTy] = *ResultOpt;
242 if (ElementType == CurrentTy) {
243 LoadInst *LI =
B.CreateLoad(ElementType,
GEP);
245 buildAssignType(
B, ElementType, LI);
249 return loadVectorFromVector(
B, SVT, DVT,
GEP, BadLoad->
getAlign());
250 if (
SAT && DVT &&
SAT->getElementType() == DVT->getElementType())
251 return loadVectorFromArray(
B, DVT,
GEP, BadLoad->
getAlign());
252 if (MAT && DVT && MAT->getElementType() == DVT->getElementType())
253 return loadVectorFromMatrixArray(
B, DVT,
GEP, MAT, BadLoad->
getAlign());
258 buildVectorFromLoadedElements(
IRBuilder<> &
B, FixedVectorType *TargetType,
259 SmallVector<Value *, 4> &LoadedElements) {
264 Value *NewVector =
B.CreateIntrinsic(
265 Intrinsic::spv_bitcast, {TargetType,
Scalar->getType()}, {
Scalar});
266 buildAssignType(
B, TargetType, NewVector);
272 buildAssignType(
B, TargetType, NewVector);
280 NewVector =
B.CreateIntrinsic(Intrinsic::spv_insertelt, {
Types}, {
Args});
281 buildAssignType(
B, TargetType, NewVector);
289 Value *Source, FixedVectorType *ArrElemVecTy,
290 Align OriginalAlign) {
293 const DataLayout &
DL =
B.GetInsertBlock()->getModule()->getDataLayout();
294 uint64_t ArrElemVecSize =
DL.getTypeAllocSize(ArrElemVecTy);
296 SmallVector<Value *, 4> LoadedElements;
299 unsigned ArrayIndex =
I / ScalarsPerArrayElement;
300 unsigned ElementIndexInArrayElem =
I % ScalarsPerArrayElement;
302 std::array<Value *, 4>
Args = {
303 B.getInt1(
false),
Source,
B.getInt32(0),
304 ConstantInt::get(
B.getInt32Ty(), ArrayIndex)};
305 auto *ElementPtr =
B.CreateIntrinsic(Intrinsic::spv_gep, {
Types}, {
Args});
306 GR->buildAssignPtr(
B, ArrElemVecTy, ElementPtr);
307 LoadInst *LoadVec =
B.CreateLoad(ArrElemVecTy, ElementPtr);
310 buildAssignType(
B, ArrElemVecTy, LoadVec);
311 LoadedElements.
push_back(makeExtractElement(
B, TargetElemTy, LoadVec,
312 ElementIndexInArrayElem));
314 return buildVectorFromLoadedElements(
B, TargetType, LoadedElements);
318 Value *Source, Align OriginalAlign) {
320 SmallVector<Value *, 4> LoadedElements;
322 const DataLayout &
DL =
B.GetInsertBlock()->getModule()->getDataLayout();
326 std::array<Value *, 4>
Args = {
B.getInt1(
false),
Source,
328 ConstantInt::get(
B.getInt32Ty(),
I)};
329 auto *ElementPtr =
B.CreateIntrinsic(Intrinsic::spv_gep, {
Types}, {
Args});
338 return buildVectorFromLoadedElements(
B, TargetType, LoadedElements);
343 Value *DstArrayPtr, ArrayType *ArrTy,
349 unsigned SrcNumElements = SrcVecTy->getNumElements();
351 SrcNumElements % ScalarsPerArrayElement == 0 &&
352 "Source vector size must be a multiple of array element vector size");
356 const DataLayout &
DL =
B.GetInsertBlock()->getModule()->getDataLayout();
357 uint64_t ArrElemVecSize =
DL.getTypeAllocSize(ArrElemVecTy);
359 for (
unsigned I = 0;
I < SrcNumElements;
I += ScalarsPerArrayElement) {
360 unsigned ArrayIndex =
I / ScalarsPerArrayElement;
362 std::array<Value *, 4>
Args = {
363 B.getInt1(
false), DstArrayPtr,
B.getInt32(0),
364 ConstantInt::get(
B.getInt32Ty(), ArrayIndex)};
365 auto *ElementPtr =
B.CreateIntrinsic(Intrinsic::spv_gep, {
Types}, {
Args});
366 GR->buildAssignPtr(
B, ArrElemVecTy, ElementPtr);
370 for (
unsigned J = 0; J < ScalarsPerArrayElement; ++J)
371 Elements.push_back(makeExtractElement(
B, ElemTy, SrcVector,
I + J));
374 Value *Vec = buildVectorFromLoadedElements(
B, ArrElemVecTy, Elements);
375 StoreInst *
SI =
B.CreateStore(Vec, ElementPtr);
382 Value *DstArrayPtr, ArrayType *ArrTy,
385 Type *ElemTy = ArrTy->getElementType();
388 assert(VecTy->getElementType() == ElemTy &&
389 "Element types of array and vector must be the same.");
392 const DataLayout &
DL =
B.GetInsertBlock()->getModule()->getDataLayout();
393 uint64_t ElemSize =
DL.getTypeAllocSize(ElemTy);
395 for (
unsigned I = 0,
E = VecTy->getNumElements();
I <
E; ++
I) {
397 std::array<Value *, 4>
Args = {
B.getInt1(
false), DstArrayPtr,
399 ConstantInt::get(
B.getInt32Ty(),
I)};
400 auto *ElementPtr =
B.CreateIntrinsic(Intrinsic::spv_gep, {
Types}, {
Args});
401 GR->buildAssignPtr(
B, ElemTy, ElementPtr);
405 E == 1 ? SrcVector : makeExtractElement(
B, ElemTy, SrcVector,
I);
406 StoreInst *
SI =
B.CreateStore(Element, ElementPtr);
414 Value *OriginalOperand) {
415 Type *ToTy = GR->findDeducedElementType(CastedOperand);
416 B.SetInsertPoint(LI);
418 Value *Output = buildLegalizedLoad(
B, ToTy, OriginalOperand, LI);
420 GR->replaceAllUsesWith(LI, Output,
true);
421 DeadInstructions.push_back(LI);
427 Type *Int32Ty = Type::getInt32Ty(
B.getContext());
431 Value *NewI =
B.CreateIntrinsic(Intrinsic::spv_insertelt, {
Types}, {
Args});
432 buildAssignType(
B,
Vector->getType(), NewI);
440 Type *Int32Ty = Type::getInt32Ty(
B.getContext());
443 Value *NewI =
B.CreateIntrinsic(Intrinsic::spv_extractelt, {
Types}, {
Args});
444 buildAssignType(
B, ElementType, NewI);
454 Type *ElemTy = VecTy->getElementType();
455 if (VecTy->getNumElements() == 1) {
457 B.CreateIntrinsic(Intrinsic::spv_bitcast, {ElemTy, VecTy}, {
Vector});
458 buildAssignType(
B, ElemTy, Scalar);
461 return makeExtractElement(
B, ElemTy,
Vector, Index);
469 FixedVectorType *DstType =
478 [[maybe_unused]]
auto dstBitWidth =
480 [[maybe_unused]]
auto srcBitWidth =
482 assert(dstBitWidth == srcBitWidth &&
483 "Unsupported bitcast between vectors of different sizes.");
486 B.CreateIntrinsic(Intrinsic::spv_bitcast, {DstType, SrcType}, {Src});
487 buildAssignType(
B, DstType, Src);
490 StoreInst *
SI =
B.CreateStore(Src, Dst);
491 SI->setAlignment(Alignment);
496 LoadInst *LI =
B.CreateLoad(DstType, Dst);
498 Value *OldValues = LI;
499 buildAssignType(
B, OldValues->
getType(), OldValues);
500 Value *NewValues = Src;
505 OldValues = makeInsertElement(
B, OldValues, Element,
I);
508 StoreInst *
SI =
B.CreateStore(OldValues, Dst);
509 SI->setAlignment(Alignment);
517 auto ResultOpt = getPointerToFirstCompatibleType(
B, Dst, Dst->getType(),
518 Src->getType(),
true);
519 assert(ResultOpt &&
"Failed to store to aggregate: "
520 "Could not find compatible memory layout.");
521 auto [
GEP, CurrentTy] = *ResultOpt;
529 if (Src->getType() == CurrentTy) {
530 StoreInst *
SI =
B.CreateStore(Src,
GEP);
531 SI->setAlignment(Alignment);
535 storeVectorFromVector(
B, Src,
GEP, Alignment);
538 if (DAT && SVT && SVT->getElementType() == DAT->getElementType()) {
539 storeArrayFromVector(
B, Src,
GEP, DAT, Alignment);
542 if (DMAT && SVT && DMAT->getElementType() == SVT->getElementType()) {
543 storeMatrixArrayFromVector(
B, Src,
GEP, DAT, Alignment);
553 Value *Dst, Align Alignment) {
554 B.SetInsertPoint(BadStore);
555 buildLegalizedStore(
B, Src, Dst, Alignment);
556 DeadInstructions.push_back(BadStore);
559 void legalizePointerCast(IntrinsicInst *
II) {
561 Value *OriginalOperand =
II->getOperand(0);
564 std::vector<Value *>
Users;
565 for (Use &U :
II->uses())
566 Users.push_back(
U.getUser());
570 transformLoad(
B, LI, CastedOperand, OriginalOperand);
575 transformStore(
B, SI,
SI->getValueOperand(), OriginalOperand,
581 if (Intrin->getIntrinsicID() == Intrinsic::spv_assign_ptr_type) {
582 DeadInstructions.push_back(Intrin);
586 if (Intrin->getIntrinsicID() == Intrinsic::spv_gep) {
587 GR->replaceAllUsesWith(CastedOperand, OriginalOperand,
592 if (Intrin->getIntrinsicID() == Intrinsic::spv_store) {
595 Alignment =
Align(
C->getZExtValue());
596 transformStore(
B, Intrin, Intrin->getArgOperand(0), OriginalOperand,
605 DeadInstructions.push_back(
II);
609 SPIRVLegalizePointerCastImpl(
const SPIRVTargetMachine &TM) : TM(TM) {}
611 bool run(Function &
F) {
612 const SPIRVSubtarget &
ST = TM.getSubtarget<SPIRVSubtarget>(
F);
613 GR =
ST.getSPIRVGlobalRegistry();
614 DeadInstructions.clear();
616 std::vector<IntrinsicInst *> WorkList;
620 if (
II &&
II->getIntrinsicID() == Intrinsic::spv_ptrcast)
621 WorkList.push_back(
II);
625 for (IntrinsicInst *
II : WorkList)
626 legalizePointerCast(
II);
628 for (Instruction *
I : DeadInstructions)
629 I->eraseFromParent();
631 return DeadInstructions.size() != 0;
635 const SPIRVTargetMachine &TM;
636 SPIRVGlobalRegistry *GR =
nullptr;
637 std::vector<Instruction *> DeadInstructions;
640class SPIRVLegalizePointerCastLegacy :
public FunctionPass {
643 SPIRVLegalizePointerCastLegacy(
const SPIRVTargetMachine &TM)
644 : FunctionPass(ID), TM(TM) {}
647 return SPIRVLegalizePointerCastImpl(TM).run(
F);
651 const SPIRVTargetMachine &TM;
661char SPIRVLegalizePointerCastLegacy::ID = 0;
663 "SPIRV legalize pointer cast pass",
false,
false)
666 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.
This is an optimization pass for GlobalISel generic memory operations.
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
@ Load
The value being inserted comes from a load (InsertElement only).
CallInst * buildIntrWithMD(Intrinsic::ID IntrID, ArrayRef< Type * > Types, Value *Arg, Value *Arg2, ArrayRef< Constant * > Imms, IRBuilder<> &B)
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Value
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.
AnalysisManager< Function > FunctionAnalysisManager
Convenience typedef for the Function analysis manager.
FunctionPass * createSPIRVLegalizePointerCastPass(SPIRVTargetMachine *TM)