243#include "llvm/IR/IntrinsicsAMDGPU.h"
263#define DEBUG_TYPE "amdgpu-lower-buffer-fat-pointers"
288 Type *remapType(
Type *SrcTy)
override;
289 void clear() { Map.clear(); }
295class BufferFatPtrToIntTypeMap :
public BufferFatPtrTypeLoweringBase {
296 using BufferFatPtrTypeLoweringBase::BufferFatPtrTypeLoweringBase;
306class BufferFatPtrToStructTypeMap :
public BufferFatPtrTypeLoweringBase {
307 using BufferFatPtrTypeLoweringBase::BufferFatPtrTypeLoweringBase;
316Type *BufferFatPtrTypeLoweringBase::remapTypeImpl(
Type *Ty) {
322 return *
Entry = remapScalar(PT);
328 return *
Entry = remapVector(VT);
336 bool IsUniqued = !TyAsStruct || TyAsStruct->
isLiteral();
345 Type *NewElem = remapTypeImpl(OldElem);
346 ElementTypes[
I] = NewElem;
347 Changed |= (OldElem != NewElem);
355 return *
Entry = ArrayType::get(ElementTypes[0], ArrTy->getNumElements());
357 return *
Entry = FunctionType::get(ElementTypes[0],
367 SmallString<16>
Name(STy->getName());
375Type *BufferFatPtrTypeLoweringBase::remapType(
Type *SrcTy) {
376 return remapTypeImpl(SrcTy);
379Type *BufferFatPtrToStructTypeMap::remapScalar(PointerType *PT) {
380 LLVMContext &Ctx = PT->getContext();
385Type *BufferFatPtrToStructTypeMap::remapVector(VectorType *VT) {
386 ElementCount
EC = VT->getElementCount();
387 LLVMContext &Ctx = VT->getContext();
406 if (!ST->isLiteral() || ST->getNumElements() != 2)
412 return MaybeRsrc && MaybeOff &&
421 return isBufferFatPtrOrVector(U.get()->getType());
434class StoreFatPtrsAsIntsAndExpandMemcpyVisitor
435 :
public InstVisitor<StoreFatPtrsAsIntsAndExpandMemcpyVisitor, bool> {
436 BufferFatPtrToIntTypeMap *TypeMap;
441 const TargetTransformInfo *
TTI;
453 StoreFatPtrsAsIntsAndExpandMemcpyVisitor(BufferFatPtrToIntTypeMap *TypeMap,
454 const DataLayout &
DL,
456 : TypeMap(TypeMap), IRB(Ctx, InstSimplifyFolder(
DL)) {}
458 ScalarEvolution *SE);
460 bool visitInstruction(Instruction &
I) {
return false; }
461 bool visitAllocaInst(AllocaInst &
I);
462 bool visitLoadInst(LoadInst &LI);
463 bool visitStoreInst(StoreInst &SI);
464 bool visitGetElementPtrInst(GetElementPtrInst &
I);
466 bool visitMemCpyInst(MemCpyInst &MCI);
467 bool visitMemMoveInst(MemMoveInst &MMI);
468 bool visitMemSetInst(MemSetInst &MSI);
469 bool visitMemSetPatternInst(MemSetPatternInst &MSPI);
473Value *StoreFatPtrsAsIntsAndExpandMemcpyVisitor::fatPtrsToInts(
478 return IRB.CreatePtrToInt(V, To, Name +
".int");
484 Type *FromPart = AT->getArrayElementType();
486 for (
uint64_t I = 0,
E = AT->getArrayNumElements();
I <
E; ++
I) {
489 fatPtrsToInts(
Field, FromPart, ToPart, Name +
"." + Twine(
I));
490 Ret = IRB.CreateInsertValue(Ret, NewField,
I);
493 for (
auto [Idx, FromPart, ToPart] :
495 Value *
Field = IRB.CreateExtractValue(V, Idx);
497 fatPtrsToInts(
Field, FromPart, ToPart, Name +
"." + Twine(Idx));
498 Ret = IRB.CreateInsertValue(Ret, NewField, Idx);
504Value *StoreFatPtrsAsIntsAndExpandMemcpyVisitor::intsToFatPtrs(
509 Value *Cast = IRB.CreateIntToPtr(V, To, Name +
".ptr");
519 for (
uint64_t I = 0,
E = AT->getArrayNumElements();
I <
E; ++
I) {
522 intsToFatPtrs(
Field, FromPart, ToPart, Name +
"." + Twine(
I));
523 Ret = IRB.CreateInsertValue(Ret, NewField,
I);
526 for (
auto [Idx, FromPart, ToPart] :
528 Value *
Field = IRB.CreateExtractValue(V, Idx);
530 intsToFatPtrs(
Field, FromPart, ToPart, Name +
"." + Twine(Idx));
531 Ret = IRB.CreateInsertValue(Ret, NewField, Idx);
537bool StoreFatPtrsAsIntsAndExpandMemcpyVisitor::processFunction(
538 Function &
F,
const TargetTransformInfo *
TTI, ScalarEvolution *SE) {
559bool StoreFatPtrsAsIntsAndExpandMemcpyVisitor::visitAllocaInst(AllocaInst &
I) {
560 Type *Ty =
I.getAllocatedType();
561 Type *NewTy = TypeMap->remapType(Ty);
564 I.setAllocatedType(NewTy);
568bool StoreFatPtrsAsIntsAndExpandMemcpyVisitor::visitGetElementPtrInst(
569 GetElementPtrInst &
I) {
570 Type *Ty =
I.getSourceElementType();
571 Type *NewTy = TypeMap->remapType(Ty);
576 I.setSourceElementType(NewTy);
577 I.setResultElementType(TypeMap->remapType(
I.getResultElementType()));
581bool StoreFatPtrsAsIntsAndExpandMemcpyVisitor::visitLoadInst(LoadInst &LI) {
583 Type *IntTy = TypeMap->remapType(Ty);
587 IRB.SetInsertPoint(&LI);
589 NLI->mutateType(IntTy);
590 NLI = IRB.Insert(NLI);
593 Value *CastBack = intsToFatPtrs(NLI, IntTy, Ty, NLI->getName());
599bool StoreFatPtrsAsIntsAndExpandMemcpyVisitor::visitStoreInst(StoreInst &SI) {
601 Type *Ty =
V->getType();
602 Type *IntTy = TypeMap->remapType(Ty);
606 IRB.SetInsertPoint(&SI);
607 Value *IntV = fatPtrsToInts(V, Ty, IntTy,
V->getName());
611 SI.setOperand(0, IntV);
615bool StoreFatPtrsAsIntsAndExpandMemcpyVisitor::visitMemCpyInst(
627bool StoreFatPtrsAsIntsAndExpandMemcpyVisitor::visitMemMoveInst(
633 "memmove() on buffer descriptors is not implemented because pointer "
634 "comparison on buffer descriptors isn't implemented\n");
637bool StoreFatPtrsAsIntsAndExpandMemcpyVisitor::visitMemSetInst(
646bool StoreFatPtrsAsIntsAndExpandMemcpyVisitor::visitMemSetPatternInst(
647 MemSetPatternInst &MSPI) {
676class LegalizeBufferContentTypesVisitor
677 :
public InstVisitor<LegalizeBufferContentTypesVisitor, bool> {
678 friend class InstVisitor<LegalizeBufferContentTypesVisitor, bool>;
682 const DataLayout &
DL;
684 ScalarEvolution *SE =
nullptr;
694 const TargetMachine *TM;
695 const GCNSubtarget *ST =
nullptr;
699 Type *scalarArrayTypeAsVector(
Type *MaybeArrayType);
700 Value *arrayToVector(
Value *V,
Type *TargetType,
const Twine &Name);
701 Value *vectorToArray(
Value *V,
Type *OrigType,
const Twine &Name);
705 struct OobProperties {
707 bool NoWrapFromMax =
false;
709 bool NoPartialOOB =
false;
711 OobProperties() =
delete;
713 OobProperties(
bool NoWrapFromMax,
bool NoPartialOOB)
714 : NoWrapFromMax(NoWrapFromMax), NoPartialOOB(NoPartialOOB) {}
744 uint64_t maxIntrinsicWidth(
Type *Ty, Align
A, OobProperties OobProps);
751 Value *makeLegalNonAggregate(
Value *V,
Type *TargetType,
const Twine &Name);
752 Value *makeIllegalNonAggregate(
Value *V,
Type *OrigType,
const Twine &Name);
766 SmallVectorImpl<VecSlice> &Slices);
768 Value *extractSlice(
Value *Vec, VecSlice S,
const Twine &Name);
769 Value *insertSlice(
Value *Whole,
Value *Part, VecSlice S,
const Twine &Name);
779 Type *intrinsicTypeFor(
Type *LegalType);
781 bool visitLoadImpl(LoadInst &OrigLI,
Type *PartType,
782 SmallVectorImpl<uint32_t> &AggIdxs,
uint64_t AggByteOffset,
783 Value *&Result,
const Twine &Name);
785 std::pair<bool, bool> visitStoreImpl(StoreInst &OrigSI,
Type *PartType,
786 SmallVectorImpl<uint32_t> &AggIdxs,
790 bool visitInstruction(Instruction &
I) {
return false; }
791 bool visitLoadInst(LoadInst &LI);
792 bool visitStoreInst(StoreInst &SI);
795 bool visitIntrinsicInst(IntrinsicInst &
II);
796 bool visitAddrSpaceCastInst(AddrSpaceCastInst &ASCI);
799 LegalizeBufferContentTypesVisitor(
const DataLayout &
DL, LLVMContext &Ctx,
800 const TargetMachine *TM)
801 : IRB(Ctx, InstSimplifyFolder(
DL)),
DL(
DL), TM(TM) {}
806Type *LegalizeBufferContentTypesVisitor::scalarArrayTypeAsVector(
Type *
T) {
810 Type *ET = AT->getElementType();
813 "should have recursed");
814 if (!
DL.typeSizeEqualsStoreSize(AT))
816 "loading padded arrays from buffer fat pinters should have recursed");
820Value *LegalizeBufferContentTypesVisitor::arrayToVector(
Value *V,
825 unsigned EC = VT->getNumElements();
826 for (
auto I : iota_range<unsigned>(0, EC,
false)) {
827 Value *Elem = IRB.CreateExtractValue(V,
I, Name +
".elem." + Twine(
I));
828 VectorRes = IRB.CreateInsertElement(VectorRes, Elem,
I,
829 Name +
".as.vec." + Twine(
I));
834Value *LegalizeBufferContentTypesVisitor::vectorToArray(
Value *V,
839 unsigned EC = AT->getNumElements();
840 for (
auto I : iota_range<unsigned>(0, EC,
false)) {
841 Value *Elem = IRB.CreateExtractElement(V,
I, Name +
".elem." + Twine(
I));
842 ArrayRes = IRB.CreateInsertValue(ArrayRes, Elem,
I,
843 Name +
".as.array." + Twine(
I));
848LegalizeBufferContentTypesVisitor::OobProperties
849LegalizeBufferContentTypesVisitor::analyzeOobProperties(
Value *Ptr,
Type *Ty,
851 OobProperties
Result(
false,
false);
854 return OobProperties(
true,
true);
860 const SCEV *PtrOp = SE->
getSCEV(Ptr);
866 Value *PtrBaseVal = PtrBase->getValue();
873 auto NumRecordsIfKnown = ZeroBasePointerToNumRecords.
find(PtrBaseVal);
874 if (NumRecordsIfKnown == ZeroBasePointerToNumRecords.
end())
877 unsigned TypeSize =
DL.getTypeStoreSize(Ty).getKnownMinValue();
882 Result.NoWrapFromMax =
true;
886 if (!NumRecordsIfKnown->second)
888 const SCEV *NumRecords = SE->
getSCEV(NumRecordsIfKnown->second);
891 std::optional<unsigned> MaybeNumRecordsWidth =
893 if (!MaybeNumRecordsWidth)
895 unsigned NumRecordsWidth = *MaybeNumRecordsWidth;
896 Type *NumRecordsTy = IRB.getIntNTy(NumRecordsWidth);
898 Type *CompareTy = IRB.getInt64Ty();
906 Result.NoPartialOOB =
true;
908 const SCEV *BoundsDiff =
913 Result.NoPartialOOB =
true;
918LegalizeBufferContentTypesVisitor::maxIntrinsicWidth(
Type *
T, Align
A,
919 OobProperties OobProps) {
925 TypeSize ElemBits =
DL.getTypeSizeInBits(VT->getElementType());
932 if (!OobProps.NoWrapFromMax)
951 if (!OobProps.NoPartialOOB)
956 return Result.value() * 8;
959Type *LegalizeBufferContentTypesVisitor::legalNonAggregateForMemOp(
961 TypeSize
Size =
DL.getTypeStoreSizeInBits(
T);
963 if (!
DL.typeSizeEqualsStoreSize(
T))
964 T = IRB.getIntNTy(
Size.getFixedValue());
965 Type *ElemTy =
T->getScalarType();
971 unsigned ElemSize =
DL.getTypeSizeInBits(ElemTy).getFixedValue();
972 if (
isPowerOf2_32(ElemSize) && ElemSize >= 16 && ElemSize <= MaxWidth) {
978 Type *BestVectorElemType =
nullptr;
979 if (
Size.isKnownMultipleOf(32) && MaxWidth >= 32)
980 BestVectorElemType = IRB.getInt32Ty();
981 else if (
Size.isKnownMultipleOf(16) && MaxWidth >= 16)
982 BestVectorElemType = IRB.getInt16Ty();
984 BestVectorElemType = IRB.getInt8Ty();
985 unsigned NumCastElems =
987 if (NumCastElems == 1)
988 return BestVectorElemType;
992Value *LegalizeBufferContentTypesVisitor::makeLegalNonAggregate(
993 Value *V,
Type *TargetType,
const Twine &Name) {
994 Type *SourceType =
V->getType();
995 TypeSize SourceSize =
DL.getTypeSizeInBits(SourceType);
996 TypeSize TargetSize =
DL.getTypeSizeInBits(TargetType);
997 if (SourceSize != TargetSize) {
1000 Value *AsScalar = IRB.CreateBitCast(V, ShortScalarTy, Name +
".as.scalar");
1001 Value *Zext = IRB.CreateZExt(AsScalar, ByteScalarTy, Name +
".zext");
1003 SourceType = ByteScalarTy;
1005 return IRB.CreateBitCast(V, TargetType, Name +
".legal");
1008Value *LegalizeBufferContentTypesVisitor::makeIllegalNonAggregate(
1009 Value *V,
Type *OrigType,
const Twine &Name) {
1010 Type *LegalType =
V->getType();
1011 TypeSize LegalSize =
DL.getTypeSizeInBits(LegalType);
1012 TypeSize OrigSize =
DL.getTypeSizeInBits(OrigType);
1013 if (LegalSize != OrigSize) {
1016 Value *AsScalar = IRB.CreateBitCast(V, ByteScalarTy, Name +
".bytes.cast");
1017 Value *Trunc = IRB.CreateTrunc(AsScalar, ShortScalarTy, Name +
".trunc");
1018 return IRB.CreateBitCast(Trunc, OrigType, Name +
".orig");
1020 return IRB.CreateBitCast(V, OrigType, Name +
".real.ty");
1023Type *LegalizeBufferContentTypesVisitor::intrinsicTypeFor(
Type *LegalType) {
1027 Type *ET = VT->getElementType();
1030 if (VT->getNumElements() == 1)
1032 if (
DL.getTypeSizeInBits(LegalType) == 96 &&
DL.getTypeSizeInBits(ET) < 32)
1035 switch (VT->getNumElements()) {
1039 return IRB.getInt8Ty();
1041 return IRB.getInt16Ty();
1043 return IRB.getInt32Ty();
1053void LegalizeBufferContentTypesVisitor::getVecSlices(
1054 Type *
T,
uint64_t MaxWidth, SmallVectorImpl<VecSlice> &Slices) {
1061 DL.getTypeSizeInBits(VT->getElementType()).getFixedValue();
1063 uint64_t ElemsPer4Words = 128 / ElemBitWidth;
1064 uint64_t ElemsPer2Words = ElemsPer4Words / 2;
1065 uint64_t ElemsPerWord = ElemsPer2Words / 2;
1066 uint64_t ElemsPerShort = ElemsPerWord / 2;
1067 uint64_t ElemsPerByte = ElemsPerShort / 2;
1071 uint64_t ElemsPer3Words = ElemsPerWord * 3;
1073 uint64_t TotalElems = VT->getNumElements();
1075 auto TrySlice = [&](
unsigned MaybeLen,
unsigned Width) {
1076 if (MaybeLen > 0 && Width <= MaxWidth && Index + MaybeLen <= TotalElems) {
1077 VecSlice Slice{
Index, MaybeLen};
1084 while (Index < TotalElems) {
1085 TrySlice(ElemsPer4Words, 128) || TrySlice(ElemsPer3Words, 96) ||
1086 TrySlice(ElemsPer2Words, 64) || TrySlice(ElemsPerWord, 32) ||
1087 TrySlice(ElemsPerShort, 16) || TrySlice(ElemsPerByte, 8);
1091Value *LegalizeBufferContentTypesVisitor::extractSlice(
Value *Vec, VecSlice S,
1092 const Twine &Name) {
1096 if (S.Length == VecVT->getNumElements() && S.Index == 0)
1099 return IRB.CreateExtractElement(Vec, S.Index,
1100 Name +
".slice." + Twine(S.Index));
1102 llvm::iota_range<int>(S.Index, S.Index + S.Length,
false));
1103 return IRB.CreateShuffleVector(Vec, Mask, Name +
".slice." + Twine(S.Index));
1106Value *LegalizeBufferContentTypesVisitor::insertSlice(
Value *Whole,
Value *Part,
1108 const Twine &Name) {
1112 if (S.Length == WholeVT->getNumElements() && S.Index == 0)
1114 if (S.Length == 1) {
1115 return IRB.CreateInsertElement(Whole, Part, S.Index,
1116 Name +
".slice." + Twine(S.Index));
1121 SmallVector<int> ExtPartMask(NumElems, -1);
1126 Value *ExtPart = IRB.CreateShuffleVector(Part, ExtPartMask,
1127 Name +
".ext." + Twine(S.Index));
1129 SmallVector<int>
Mask =
1134 return IRB.CreateShuffleVector(Whole, ExtPart, Mask,
1135 Name +
".parts." + Twine(S.Index));
1138bool LegalizeBufferContentTypesVisitor::visitLoadImpl(
1139 LoadInst &OrigLI,
Type *PartType, SmallVectorImpl<uint32_t> &AggIdxs,
1142 const StructLayout *Layout =
DL.getStructLayout(ST);
1144 for (
auto [
I, ElemTy,
Offset] :
1147 Changed |= visitLoadImpl(OrigLI, ElemTy, AggIdxs,
1148 AggByteOff +
Offset.getFixedValue(), Result,
1149 Name +
"." + Twine(
I));
1155 Type *ElemTy = AT->getElementType();
1158 TypeSize ElemAllocSize =
DL.getTypeAllocSize(ElemTy);
1160 for (
auto I : llvm::iota_range<uint32_t>(0, AT->getNumElements(),
1163 Changed |= visitLoadImpl(OrigLI, ElemTy, AggIdxs,
1165 Result, Name + Twine(
I));
1175 Type *ArrayAsVecType = scalarArrayTypeAsVector(PartType);
1176 OobProperties OobProps =
1178 uint64_t MaxWidth = maxIntrinsicWidth(ArrayAsVecType, PartAlign, OobProps);
1179 Type *LegalType = legalNonAggregateForMemOp(ArrayAsVecType, MaxWidth);
1182 getVecSlices(LegalType, MaxWidth, Slices);
1183 bool HasSlices = Slices.
size() > 1;
1184 bool IsAggPart = !AggIdxs.
empty();
1186 if (!HasSlices && !IsAggPart) {
1187 Type *LoadableType = intrinsicTypeFor(LegalType);
1188 if (LoadableType == PartType)
1191 IRB.SetInsertPoint(&OrigLI);
1193 NLI->mutateType(LoadableType);
1194 NLI = IRB.Insert(NLI);
1195 NLI->setName(Name +
".loadable");
1197 LoadsRes = IRB.CreateBitCast(NLI, LegalType, Name +
".from.loadable");
1199 IRB.SetInsertPoint(&OrigLI);
1207 unsigned ElemBytes =
DL.getTypeStoreSize(ElemType);
1209 if (IsAggPart && Slices.
empty())
1211 for (VecSlice S : Slices) {
1214 int64_t ByteOffset = AggByteOff + S.Index * ElemBytes;
1216 Value *NewPtr = IRB.CreateGEP(
1218 OrigPtr->
getName() +
".off.ptr." + Twine(ByteOffset),
1221 Type *LoadableType = intrinsicTypeFor(SliceType);
1222 LoadInst *NewLI = IRB.CreateAlignedLoad(
1224 Name +
".off." + Twine(ByteOffset));
1230 Value *
Loaded = IRB.CreateBitCast(NewLI, SliceType,
1231 NewLI->
getName() +
".from.loadable");
1232 LoadsRes = insertSlice(LoadsRes, Loaded, S, Name);
1235 if (LegalType != ArrayAsVecType)
1236 LoadsRes = makeIllegalNonAggregate(LoadsRes, ArrayAsVecType, Name);
1237 if (ArrayAsVecType != PartType)
1238 LoadsRes = vectorToArray(LoadsRes, PartType, Name);
1241 Result = IRB.CreateInsertValue(Result, LoadsRes, AggIdxs, Name);
1247bool LegalizeBufferContentTypesVisitor::visitLoadInst(LoadInst &LI) {
1251 SmallVector<uint32_t> AggIdxs;
1254 bool Changed = visitLoadImpl(LI, OrigType, AggIdxs, 0, Result, LI.
getName());
1263std::pair<bool, bool> LegalizeBufferContentTypesVisitor::visitStoreImpl(
1264 StoreInst &OrigSI,
Type *PartType, SmallVectorImpl<uint32_t> &AggIdxs,
1265 uint64_t AggByteOff,
const Twine &Name) {
1267 const StructLayout *Layout =
DL.getStructLayout(ST);
1269 for (
auto [
I, ElemTy,
Offset] :
1272 Changed |= std::get<0>(visitStoreImpl(OrigSI, ElemTy, AggIdxs,
1273 AggByteOff +
Offset.getFixedValue(),
1274 Name +
"." + Twine(
I)));
1277 return std::make_pair(
Changed,
false);
1280 Type *ElemTy = AT->getElementType();
1283 TypeSize ElemAllocSize =
DL.getTypeAllocSize(ElemTy);
1285 for (
auto I : llvm::iota_range<uint32_t>(0, AT->getNumElements(),
1288 Changed |= std::get<0>(visitStoreImpl(
1289 OrigSI, ElemTy, AggIdxs,
1293 return std::make_pair(
Changed,
false);
1298 Value *NewData = OrigData;
1300 bool IsAggPart = !AggIdxs.
empty();
1302 NewData = IRB.CreateExtractValue(NewData, AggIdxs, Name);
1304 Type *ArrayAsVecType = scalarArrayTypeAsVector(PartType);
1305 if (ArrayAsVecType != PartType) {
1306 NewData = arrayToVector(NewData, ArrayAsVecType, Name);
1310 OobProperties OobProps =
1312 uint64_t MaxWidth = maxIntrinsicWidth(ArrayAsVecType, PartAlign, OobProps);
1313 Type *LegalType = legalNonAggregateForMemOp(ArrayAsVecType, MaxWidth);
1314 if (LegalType != ArrayAsVecType) {
1315 NewData = makeLegalNonAggregate(NewData, LegalType, Name);
1319 getVecSlices(LegalType, MaxWidth, Slices);
1320 bool NeedToSplit = Slices.
size() > 1 || IsAggPart;
1322 Type *StorableType = intrinsicTypeFor(LegalType);
1323 if (StorableType == PartType)
1324 return std::make_pair(
false,
false);
1325 NewData = IRB.CreateBitCast(NewData, StorableType, Name +
".storable");
1327 return std::make_pair(
true,
true);
1332 if (IsAggPart && Slices.
empty())
1334 unsigned ElemBytes =
DL.getTypeStoreSize(ElemType);
1336 for (VecSlice S : Slices) {
1339 int64_t ByteOffset = AggByteOff + S.Index * ElemBytes;
1340 Value *NewPtr = IRB.CreateGEP(
1341 IRB.getInt8Ty(), OrigPtr, IRB.getInt32(ByteOffset),
1342 OrigPtr->
getName() +
".part." + Twine(S.Index),
1345 Value *DataSlice = extractSlice(NewData, S, Name);
1346 Type *StorableType = intrinsicTypeFor(SliceType);
1347 DataSlice = IRB.CreateBitCast(DataSlice, StorableType,
1348 DataSlice->
getName() +
".storable");
1352 NewSI->setOperand(0, DataSlice);
1353 NewSI->setOperand(1, NewPtr);
1356 return std::make_pair(
true,
false);
1359bool LegalizeBufferContentTypesVisitor::visitStoreInst(StoreInst &SI) {
1362 IRB.SetInsertPoint(&SI);
1363 SmallVector<uint32_t> AggIdxs;
1364 Value *OrigData =
SI.getValueOperand();
1365 auto [
Changed, ModifiedInPlace] =
1366 visitStoreImpl(SI, OrigData->
getType(), AggIdxs, 0, OrigData->
getName());
1367 if (
Changed && !ModifiedInPlace)
1368 SI.eraseFromParent();
1372bool LegalizeBufferContentTypesVisitor::visitAddrSpaceCastInst(
1373 AddrSpaceCastInst &AI) {
1378 auto Record = ZeroBasePointerToNumRecords.
find(Src);
1379 if (Record != ZeroBasePointerToNumRecords.
end())
1380 ZeroBasePointerToNumRecords.
insert({&AI,
Record->second});
1382 ZeroBasePointerToNumRecords.
insert({&AI,
nullptr});
1386bool LegalizeBufferContentTypesVisitor::visitIntrinsicInst(IntrinsicInst &
II) {
1387 if (
II.getIntrinsicID() != Intrinsic::amdgcn_make_buffer_rsrc)
1389 ZeroBasePointerToNumRecords.
insert({&
II,
II.getOperand(2)});
1393bool LegalizeBufferContentTypesVisitor::processFunction(
Function &
F,
1394 ScalarEvolution *SE) {
1401 ZeroBasePointerToNumRecords.
clear();
1408static std::pair<Constant *, Constant *>
1411 return std::make_pair(
C->getAggregateElement(0u),
C->getAggregateElement(1u));
1416class FatPtrConstMaterializer final :
public ValueMaterializer {
1417 BufferFatPtrToStructTypeMap *TypeMap;
1423 ValueMapper InternalMapper;
1425 Constant *materializeBufferFatPtrConst(Constant *
C);
1429 FatPtrConstMaterializer(BufferFatPtrToStructTypeMap *TypeMap,
1432 InternalMapper(UnderlyingMap,
RF_None, TypeMap, this) {}
1433 ~FatPtrConstMaterializer() =
default;
1439Constant *FatPtrConstMaterializer::materializeBufferFatPtrConst(Constant *
C) {
1440 Type *SrcTy =
C->getType();
1442 if (
C->isNullValue())
1443 return ConstantAggregateZero::getNullValue(NewTy);
1456 if (Constant *S =
VC->getSplatValue()) {
1461 auto EC =
VC->getType()->getElementCount();
1467 for (
Value *
Op :
VC->operand_values()) {
1482 "fat pointer) values are not supported");
1486 "constant exprs containing ptr addrspace(7) (buffer "
1487 "fat pointer) values should have been expanded earlier");
1492Value *FatPtrConstMaterializer::materialize(
Value *V) {
1500 return materializeBufferFatPtrConst(
C);
1508class SplitPtrStructs :
public InstVisitor<SplitPtrStructs, PtrParts> {
1551 void processConditionals();
1601void SplitPtrStructs::copyMetadata(
Value *Dest,
Value *Src) {
1605 if (!DestI || !SrcI)
1608 DestI->copyMetadata(*SrcI);
1613 "of something that wasn't rewritten");
1614 auto *RsrcEntry = &RsrcParts[
V];
1615 auto *OffEntry = &OffParts[
V];
1616 if (*RsrcEntry && *OffEntry)
1617 return {*RsrcEntry, *OffEntry};
1621 return {*RsrcEntry = Rsrc, *OffEntry =
Off};
1624 IRBuilder<InstSimplifyFolder>::InsertPointGuard Guard(IRB);
1629 return {*RsrcEntry = Rsrc, *OffEntry =
Off};
1632 IRB.SetInsertPoint(*
I->getInsertionPointAfterDef());
1633 IRB.SetCurrentDebugLocation(
I->getDebugLoc());
1635 IRB.SetInsertPointPastAllocas(
A->getParent());
1636 IRB.SetCurrentDebugLocation(
DebugLoc());
1638 Value *Rsrc = IRB.CreateExtractValue(V, 0,
V->getName() +
".rsrc");
1639 Value *
Off = IRB.CreateExtractValue(V, 1,
V->getName() +
".off");
1640 return {*RsrcEntry = Rsrc, *OffEntry =
Off};
1653 V =
GEP->getPointerOperand();
1655 V = ASC->getPointerOperand();
1659void SplitPtrStructs::getPossibleRsrcRoots(Instruction *
I,
1660 SmallPtrSetImpl<Value *> &Roots,
1661 SmallPtrSetImpl<Value *> &Seen) {
1665 for (
Value *In :
PHI->incoming_values()) {
1672 if (!Seen.
insert(SI).second)
1687void SplitPtrStructs::processConditionals() {
1688 SmallDenseMap<Value *, Value *> FoundRsrcs;
1689 SmallPtrSet<Value *, 4> Roots;
1690 SmallPtrSet<Value *, 4> Seen;
1691 for (Instruction *
I : Conditionals) {
1693 Value *Rsrc = RsrcParts[
I];
1695 assert(Rsrc && Off &&
"must have visited conditionals by now");
1697 std::optional<Value *> MaybeRsrc;
1698 auto MaybeFoundRsrc = FoundRsrcs.
find(
I);
1699 if (MaybeFoundRsrc != FoundRsrcs.
end()) {
1700 MaybeRsrc = MaybeFoundRsrc->second;
1702 IRBuilder<InstSimplifyFolder>::InsertPointGuard Guard(IRB);
1705 getPossibleRsrcRoots(
I, Roots, Seen);
1708 for (
Value *V : Roots)
1710 for (
Value *V : Seen)
1722 if (Diff.size() == 1) {
1723 Value *RootVal = *Diff.begin();
1727 MaybeRsrc = std::get<0>(getPtrParts(RootVal));
1729 MaybeRsrc = RootVal;
1737 IRB.SetInsertPoint(*
PHI->getInsertionPointAfterDef());
1738 IRB.SetCurrentDebugLocation(
PHI->getDebugLoc());
1740 NewRsrc = *MaybeRsrc;
1743 auto *RsrcPHI = IRB.CreatePHI(RsrcTy,
PHI->getNumIncomingValues());
1744 RsrcPHI->takeName(Rsrc);
1745 for (
auto [V, BB] :
llvm::zip(
PHI->incoming_values(),
PHI->blocks())) {
1746 Value *VRsrc = std::get<0>(getPtrParts(V));
1747 RsrcPHI->addIncoming(VRsrc, BB);
1749 copyMetadata(RsrcPHI,
PHI);
1754 auto *NewOff = IRB.CreatePHI(OffTy,
PHI->getNumIncomingValues());
1755 NewOff->takeName(Off);
1756 for (
auto [V, BB] :
llvm::zip(
PHI->incoming_values(),
PHI->blocks())) {
1757 assert(OffParts.
count(V) &&
"An offset part had to be created by now");
1758 Value *VOff = std::get<1>(getPtrParts(V));
1759 NewOff->addIncoming(VOff, BB);
1761 copyMetadata(NewOff,
PHI);
1771 RsrcInst->replaceAllUsesWith(NewRsrc);
1775 OffInst->replaceAllUsesWith(NewOff);
1780 for (
Value *V : Seen)
1781 FoundRsrcs[
V] = NewRsrc;
1786 if (RsrcInst != *MaybeRsrc) {
1788 RsrcInst->replaceAllUsesWith(*MaybeRsrc);
1791 for (
Value *V : Seen)
1792 FoundRsrcs[
V] = *MaybeRsrc;
1800void SplitPtrStructs::killAndReplaceSplitInstructions(
1801 SmallVectorImpl<Instruction *> &Origs) {
1802 for (Instruction *
I : ConditionalTemps)
1803 I->eraseFromParent();
1805 for (Instruction *
I : Origs) {
1811 for (DbgVariableRecord *Dbg : Dbgs) {
1812 auto &
DL =
I->getDataLayout();
1814 "We should've RAUW'd away loads, stores, etc. at this point");
1815 DbgVariableRecord *OffDbg =
Dbg->clone();
1816 auto [Rsrc,
Off] = getPtrParts(
I);
1818 int64_t RsrcSz =
DL.getTypeSizeInBits(Rsrc->
getType());
1819 int64_t OffSz =
DL.getTypeSizeInBits(
Off->getType());
1821 std::optional<DIExpression *> RsrcExpr =
1824 std::optional<DIExpression *> OffExpr =
1835 Dbg->setExpression(*RsrcExpr);
1836 Dbg->replaceVariableLocationOp(
I, Rsrc);
1843 I->replaceUsesWithIf(
Poison, [&](
const Use &U) ->
bool {
1849 if (
I->use_empty()) {
1850 I->eraseFromParent();
1853 IRB.SetInsertPoint(*
I->getInsertionPointAfterDef());
1854 IRB.SetCurrentDebugLocation(
I->getDebugLoc());
1855 auto [Rsrc,
Off] = getPtrParts(
I);
1857 Struct = IRB.CreateInsertValue(Struct, Rsrc, 0);
1858 Struct = IRB.CreateInsertValue(Struct, Off, 1);
1859 copyMetadata(Struct,
I);
1861 I->replaceAllUsesWith(Struct);
1862 I->eraseFromParent();
1866void SplitPtrStructs::setAlign(CallInst *Intr, Align
A,
unsigned RsrcArgIdx) {
1868 Intr->
addParamAttr(RsrcArgIdx, Attribute::getWithAlignment(Ctx,
A));
1874 case AtomicOrdering::Release:
1875 case AtomicOrdering::AcquireRelease:
1876 case AtomicOrdering::SequentiallyConsistent:
1877 IRB.CreateFence(AtomicOrdering::Release, SSID);
1887 case AtomicOrdering::Acquire:
1888 case AtomicOrdering::AcquireRelease:
1889 case AtomicOrdering::SequentiallyConsistent:
1890 IRB.CreateFence(AtomicOrdering::Acquire, SSID);
1897Value *SplitPtrStructs::handleMemoryInst(Instruction *
I,
Value *Arg,
Value *Ptr,
1898 Type *Ty, Align Alignment,
1901 IRB.SetInsertPoint(
I);
1903 auto [Rsrc,
Off] = getPtrParts(Ptr);
1906 Args.push_back(Arg);
1907 Args.push_back(Rsrc);
1908 Args.push_back(Off);
1909 insertPreMemOpFence(Order, SSID);
1913 Args.push_back(IRB.getInt32(0));
1918 Args.push_back(IRB.getInt32(Aux));
1922 IID = Order == AtomicOrdering::NotAtomic
1923 ? Intrinsic::amdgcn_raw_ptr_buffer_load
1924 : Intrinsic::amdgcn_raw_ptr_atomic_buffer_load;
1926 IID = Intrinsic::amdgcn_raw_ptr_buffer_store;
1928 switch (RMW->getOperation()) {
1930 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_swap;
1933 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_add;
1936 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_sub;
1939 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_and;
1942 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_or;
1945 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_xor;
1948 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_smax;
1951 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_smin;
1954 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_umax;
1957 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_umin;
1960 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_fadd;
1963 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_fmax;
1966 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_fmin;
1969 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_cond_sub_u32;
1972 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_sub_clamp_u32;
1976 "atomic floating point subtraction not supported for "
1977 "buffer resources and should've been expanded away");
1982 "atomic floating point fmaximum not supported for "
1983 "buffer resources and should've been expanded away");
1988 "atomic floating point fminimum not supported for "
1989 "buffer resources and should've been expanded away");
1994 "atomic floating point fmaximumnum not supported for "
1995 "buffer resources and should've been expanded away");
2000 "atomic floating point fminimumnum not supported for "
2001 "buffer resources and should've been expanded away");
2006 "atomic nand not supported for buffer resources and "
2007 "should've been expanded away");
2012 "wrapping increment/decrement not supported for "
2013 "buffer resources and should've been expanded away");
2020 CallInst *
Call = IRB.CreateIntrinsicWithoutFolding(IID, Ty, Args);
2021 copyMetadata(
Call,
I);
2022 setAlign(
Call, Alignment, Arg ? 1 : 0);
2025 insertPostMemOpFence(Order, SSID);
2029 I->replaceAllUsesWith(
Call);
2033PtrParts SplitPtrStructs::visitInstruction(Instruction &
I) {
2034 return {
nullptr,
nullptr};
2037PtrParts SplitPtrStructs::visitLoadInst(LoadInst &LI) {
2039 return {
nullptr,
nullptr};
2043 return {
nullptr,
nullptr};
2046PtrParts SplitPtrStructs::visitStoreInst(StoreInst &SI) {
2048 return {
nullptr,
nullptr};
2049 Value *Arg =
SI.getValueOperand();
2050 handleMemoryInst(&SI, Arg,
SI.getPointerOperand(), Arg->
getType(),
2051 SI.getAlign(),
SI.getOrdering(),
SI.isVolatile(),
2052 SI.getSyncScopeID());
2053 return {
nullptr,
nullptr};
2056PtrParts SplitPtrStructs::visitAtomicRMWInst(AtomicRMWInst &AI) {
2058 return {
nullptr,
nullptr};
2063 return {
nullptr,
nullptr};
2068PtrParts SplitPtrStructs::visitAtomicCmpXchgInst(AtomicCmpXchgInst &AI) {
2071 return {
nullptr,
nullptr};
2072 IRB.SetInsertPoint(&AI);
2077 bool IsNonTemporal = AI.
getMetadata(LLVMContext::MD_nontemporal);
2079 auto [Rsrc,
Off] = getPtrParts(Ptr);
2080 insertPreMemOpFence(Order, SSID);
2087 CallInst *
Call = IRB.CreateIntrinsicWithoutFolding(
2088 Intrinsic::amdgcn_raw_ptr_buffer_atomic_cmpswap, Ty,
2090 IRB.getInt32(0), IRB.getInt32(Aux)});
2091 copyMetadata(
Call, &AI);
2094 insertPostMemOpFence(Order, SSID);
2097 Res = IRB.CreateInsertValue(Res,
Call, 0);
2099 Res = IRB.CreateInsertValue(Res, Succeeded, 1);
2102 return {
nullptr,
nullptr};
2105PtrParts SplitPtrStructs::visitGetElementPtrInst(GetElementPtrInst &
GEP) {
2106 using namespace llvm::PatternMatch;
2107 Value *Ptr =
GEP.getPointerOperand();
2109 return {
nullptr,
nullptr};
2110 IRB.SetInsertPoint(&
GEP);
2112 auto [Rsrc,
Off] = getPtrParts(Ptr);
2113 const DataLayout &
DL =
GEP.getDataLayout();
2114 bool IsNUW =
GEP.hasNoUnsignedWrap();
2115 bool IsNUSW =
GEP.hasNoUnsignedSignedWrap();
2126 GEP.mutateType(FatPtrTy);
2128 GEP.mutateType(ResTy);
2130 if (BroadcastsPtr) {
2131 Rsrc = IRB.CreateVectorSplat(ResRsrcVecTy->getElementCount(), Rsrc,
2133 Off = IRB.CreateVectorSplat(ResRsrcVecTy->getElementCount(), Off,
2141 bool HasNonNegativeOff =
false;
2143 HasNonNegativeOff = !CI->isNegative();
2149 NewOff = IRB.CreateAdd(Off, OffAccum,
"",
2150 IsNUW || (IsNUSW && HasNonNegativeOff),
2153 copyMetadata(NewOff, &
GEP);
2156 return {Rsrc, NewOff};
2159PtrParts SplitPtrStructs::visitPtrToIntInst(PtrToIntInst &PI) {
2162 return {
nullptr,
nullptr};
2163 IRB.SetInsertPoint(&PI);
2168 auto [Rsrc,
Off] = getPtrParts(Ptr);
2174 Res = IRB.CreateIntCast(Off, ResTy,
false,
2177 Value *RsrcInt = IRB.CreatePtrToInt(Rsrc, ResTy, PI.
getName() +
".rsrc");
2178 Value *Shl = IRB.CreateShl(
2181 "", Width >= FatPtrWidth, Width > FatPtrWidth);
2182 Value *OffCast = IRB.CreateIntCast(Off, ResTy,
false,
2184 Res = IRB.CreateOr(Shl, OffCast);
2187 copyMetadata(Res, &PI);
2191 return {
nullptr,
nullptr};
2194PtrParts SplitPtrStructs::visitPtrToAddrInst(PtrToAddrInst &PA) {
2197 return {
nullptr,
nullptr};
2198 IRB.SetInsertPoint(&PA);
2200 auto [Rsrc,
Off] = getPtrParts(Ptr);
2201 Value *Res = IRB.CreateIntCast(Off, PA.
getType(),
false);
2202 copyMetadata(Res, &PA);
2206 return {
nullptr,
nullptr};
2209PtrParts SplitPtrStructs::visitIntToPtrInst(IntToPtrInst &IP) {
2211 return {
nullptr,
nullptr};
2212 IRB.SetInsertPoint(&IP);
2221 Type *RsrcTy = RetTy->getElementType(0);
2222 Type *OffTy = RetTy->getElementType(1);
2231 RsrcInt = IRB.CreateIntCast(RsrcPart, RsrcIntTy,
false);
2233 Value *Rsrc = IRB.CreateIntToPtr(RsrcInt, RsrcTy, IP.
getName() +
".rsrc");
2235 IRB.CreateIntCast(
Int, OffTy,
false, IP.
getName() +
".off");
2237 copyMetadata(Rsrc, &IP);
2242PtrParts SplitPtrStructs::visitAddrSpaceCastInst(AddrSpaceCastInst &
I) {
2246 return {
nullptr,
nullptr};
2247 IRB.SetInsertPoint(&
I);
2250 if (
In->getType() ==
I.getType()) {
2251 auto [Rsrc,
Off] = getPtrParts(In);
2257 Type *RsrcTy = ResTy->getElementType(0);
2258 Type *OffTy = ResTy->getElementType(1);
2264 if (InConst && InConst->isNullValue()) {
2267 return {NullRsrc, ZeroOff};
2273 return {PoisonRsrc, PoisonOff};
2279 return {UndefRsrc, UndefOff};
2284 "only buffer resources (addrspace 8) and null/poison pointers can be "
2285 "cast to buffer fat pointers (addrspace 7)");
2287 return {
In, ZeroOff};
2290PtrParts SplitPtrStructs::visitICmpInst(ICmpInst &Cmp) {
2293 return {
nullptr,
nullptr};
2295 IRB.SetInsertPoint(&Cmp);
2296 ICmpInst::Predicate Pred =
Cmp.getPredicate();
2298 assert((Pred == ICmpInst::ICMP_EQ || Pred == ICmpInst::ICMP_NE) &&
2299 "Pointer comparison is only equal or unequal");
2300 auto [LhsRsrc, LhsOff] = getPtrParts(Lhs);
2301 auto [RhsRsrc, RhsOff] = getPtrParts(Rhs);
2302 Value *Res = IRB.CreateICmp(Pred, LhsOff, RhsOff);
2303 copyMetadata(Res, &Cmp);
2306 Cmp.replaceAllUsesWith(Res);
2307 return {
nullptr,
nullptr};
2310PtrParts SplitPtrStructs::visitFreezeInst(FreezeInst &
I) {
2312 return {
nullptr,
nullptr};
2313 IRB.SetInsertPoint(&
I);
2314 auto [Rsrc,
Off] = getPtrParts(
I.getOperand(0));
2316 Value *RsrcRes = IRB.CreateFreeze(Rsrc,
I.getName() +
".rsrc");
2317 copyMetadata(RsrcRes, &
I);
2318 Value *OffRes = IRB.CreateFreeze(Off,
I.getName() +
".off");
2319 copyMetadata(OffRes, &
I);
2321 return {RsrcRes, OffRes};
2324PtrParts SplitPtrStructs::visitExtractElementInst(ExtractElementInst &
I) {
2326 return {
nullptr,
nullptr};
2327 IRB.SetInsertPoint(&
I);
2328 Value *Vec =
I.getVectorOperand();
2329 Value *Idx =
I.getIndexOperand();
2330 auto [Rsrc,
Off] = getPtrParts(Vec);
2332 Value *RsrcRes = IRB.CreateExtractElement(Rsrc, Idx,
I.getName() +
".rsrc");
2333 copyMetadata(RsrcRes, &
I);
2334 Value *OffRes = IRB.CreateExtractElement(Off, Idx,
I.getName() +
".off");
2335 copyMetadata(OffRes, &
I);
2337 return {RsrcRes, OffRes};
2340PtrParts SplitPtrStructs::visitInsertElementInst(InsertElementInst &
I) {
2344 return {
nullptr,
nullptr};
2345 IRB.SetInsertPoint(&
I);
2346 Value *Vec =
I.getOperand(0);
2347 Value *Elem =
I.getOperand(1);
2348 Value *Idx =
I.getOperand(2);
2349 auto [VecRsrc, VecOff] = getPtrParts(Vec);
2350 auto [ElemRsrc, ElemOff] = getPtrParts(Elem);
2353 IRB.CreateInsertElement(VecRsrc, ElemRsrc, Idx,
I.getName() +
".rsrc");
2354 copyMetadata(RsrcRes, &
I);
2356 IRB.CreateInsertElement(VecOff, ElemOff, Idx,
I.getName() +
".off");
2357 copyMetadata(OffRes, &
I);
2359 return {RsrcRes, OffRes};
2362PtrParts SplitPtrStructs::visitShuffleVectorInst(ShuffleVectorInst &
I) {
2365 return {
nullptr,
nullptr};
2366 IRB.SetInsertPoint(&
I);
2369 Value *V2 =
I.getOperand(1);
2370 ArrayRef<int>
Mask =
I.getShuffleMask();
2371 auto [V1Rsrc, V1Off] = getPtrParts(
V1);
2372 auto [V2Rsrc, V2Off] = getPtrParts(V2);
2375 IRB.CreateShuffleVector(V1Rsrc, V2Rsrc, Mask,
I.getName() +
".rsrc");
2376 copyMetadata(RsrcRes, &
I);
2378 IRB.CreateShuffleVector(V1Off, V2Off, Mask,
I.getName() +
".off");
2379 copyMetadata(OffRes, &
I);
2381 return {RsrcRes, OffRes};
2384PtrParts SplitPtrStructs::visitPHINode(PHINode &
PHI) {
2386 return {
nullptr,
nullptr};
2387 IRB.SetInsertPoint(*
PHI.getInsertionPointAfterDef());
2393 Value *TmpRsrc = IRB.CreateExtractValue(&
PHI, 0,
PHI.getName() +
".rsrc");
2394 Value *TmpOff = IRB.CreateExtractValue(&
PHI, 1,
PHI.getName() +
".off");
2395 Conditionals.push_back(&
PHI);
2397 return {TmpRsrc, TmpOff};
2400PtrParts SplitPtrStructs::visitSelectInst(SelectInst &SI) {
2402 return {
nullptr,
nullptr};
2403 IRB.SetInsertPoint(&SI);
2406 Value *True =
SI.getTrueValue();
2407 Value *False =
SI.getFalseValue();
2408 auto [TrueRsrc, TrueOff] = getPtrParts(True);
2409 auto [FalseRsrc, FalseOff] = getPtrParts(False);
2412 IRB.CreateSelect(
Cond, TrueRsrc, FalseRsrc,
SI.getName() +
".rsrc", &SI);
2413 copyMetadata(RsrcRes, &SI);
2414 Conditionals.push_back(&SI);
2416 IRB.CreateSelect(
Cond, TrueOff, FalseOff,
SI.getName() +
".off", &SI);
2417 copyMetadata(OffRes, &SI);
2419 return {RsrcRes, OffRes};
2430 case Intrinsic::amdgcn_make_buffer_rsrc:
2431 case Intrinsic::ptrmask:
2432 case Intrinsic::invariant_start:
2433 case Intrinsic::invariant_end:
2434 case Intrinsic::launder_invariant_group:
2435 case Intrinsic::strip_invariant_group:
2436 case Intrinsic::memcpy:
2437 case Intrinsic::memcpy_inline:
2438 case Intrinsic::memmove:
2439 case Intrinsic::memset:
2440 case Intrinsic::memset_inline:
2441 case Intrinsic::experimental_memset_pattern:
2442 case Intrinsic::amdgcn_load_to_lds:
2443 case Intrinsic::amdgcn_load_async_to_lds:
2448PtrParts SplitPtrStructs::visitIntrinsicInst(IntrinsicInst &
I) {
2453 case Intrinsic::amdgcn_make_buffer_rsrc: {
2455 return {
nullptr,
nullptr};
2457 Value *Stride =
I.getArgOperand(1);
2458 Value *NumRecords =
I.getArgOperand(2);
2461 Type *RsrcType = SplitType->getElementType(0);
2462 Type *OffType = SplitType->getElementType(1);
2463 IRB.SetInsertPoint(&
I);
2464 Value *Rsrc = IRB.CreateIntrinsic(
2465 IID, {RsrcType,
Base->getType(), NumRecords->
getType()},
2467 copyMetadata(Rsrc, &
I);
2471 return {Rsrc,
Zero};
2473 case Intrinsic::ptrmask: {
2474 Value *Ptr =
I.getArgOperand(0);
2476 return {
nullptr,
nullptr};
2478 IRB.SetInsertPoint(&
I);
2479 auto [Rsrc,
Off] = getPtrParts(Ptr);
2480 if (
Mask->getType() !=
Off->getType())
2482 "pointer (data layout not set up correctly?)");
2483 Value *OffRes = IRB.CreateAnd(Off, Mask,
I.getName() +
".off");
2484 copyMetadata(OffRes, &
I);
2486 return {Rsrc, OffRes};
2490 case Intrinsic::invariant_start: {
2491 Value *Ptr =
I.getArgOperand(1);
2493 return {
nullptr,
nullptr};
2494 IRB.SetInsertPoint(&
I);
2495 auto [Rsrc,
Off] = getPtrParts(Ptr);
2497 auto *NewRsrc = IRB.CreateIntrinsic(IID, {NewTy}, {
I.getOperand(0), Rsrc});
2498 copyMetadata(NewRsrc, &
I);
2501 I.replaceAllUsesWith(NewRsrc);
2502 return {
nullptr,
nullptr};
2504 case Intrinsic::invariant_end: {
2505 Value *RealPtr =
I.getArgOperand(2);
2507 return {
nullptr,
nullptr};
2508 IRB.SetInsertPoint(&
I);
2509 Value *RealRsrc = getPtrParts(RealPtr).first;
2510 Value *InvPtr =
I.getArgOperand(0);
2512 Value *NewRsrc = IRB.CreateIntrinsic(IID, {RealRsrc->
getType()},
2513 {InvPtr,
Size, RealRsrc});
2514 copyMetadata(NewRsrc, &
I);
2517 I.replaceAllUsesWith(NewRsrc);
2518 return {
nullptr,
nullptr};
2520 case Intrinsic::launder_invariant_group:
2521 case Intrinsic::strip_invariant_group: {
2522 Value *Ptr =
I.getArgOperand(0);
2524 return {
nullptr,
nullptr};
2525 IRB.SetInsertPoint(&
I);
2526 auto [Rsrc,
Off] = getPtrParts(Ptr);
2527 Value *NewRsrc = IRB.CreateIntrinsic(IID, {Rsrc->
getType()}, {Rsrc});
2528 copyMetadata(NewRsrc, &
I);
2531 return {NewRsrc,
Off};
2533 case Intrinsic::amdgcn_load_to_lds:
2534 case Intrinsic::amdgcn_load_async_to_lds: {
2535 Value *Ptr =
I.getArgOperand(0);
2537 return {
nullptr,
nullptr};
2538 IRB.SetInsertPoint(&
I);
2539 auto [Rsrc,
Off] = getPtrParts(Ptr);
2540 Value *LDSPtr =
I.getArgOperand(1);
2541 Value *LoadSize =
I.getArgOperand(2);
2542 Value *ImmOff =
I.getArgOperand(3);
2543 Value *Aux =
I.getArgOperand(4);
2544 Value *SOffset = IRB.getInt32(0);
2546 IID == Intrinsic::amdgcn_load_to_lds
2547 ? Intrinsic::amdgcn_raw_ptr_buffer_load_lds
2548 : Intrinsic::amdgcn_raw_ptr_buffer_load_async_lds;
2549 Instruction *NewLoad = IRB.CreateIntrinsicWithoutFolding(
2550 NewIntr, {}, {Rsrc, LDSPtr, LoadSize,
Off, SOffset, ImmOff, Aux});
2551 copyMetadata(NewLoad, &
I);
2553 I.replaceAllUsesWith(NewLoad);
2554 return {
nullptr,
nullptr};
2557 return {
nullptr,
nullptr};
2560void SplitPtrStructs::processFunction(
Function &
F) {
2562 SmallVector<Instruction *, 0> Originals(
2564 LLVM_DEBUG(
dbgs() <<
"Splitting pointer structs in function: " <<
F.getName()
2566 for (Instruction *
I : Originals) {
2574 assert(((Rsrc && Off) || (!Rsrc && !Off)) &&
2575 "Can't have a resource but no offset");
2577 RsrcParts[
I] = Rsrc;
2581 processConditionals();
2582 killAndReplaceSplitInstructions(Originals);
2588 Conditionals.clear();
2589 ConditionalTemps.clear();
2593class AMDGPULowerBufferFatPointers :
public ModulePass {
2597 AMDGPULowerBufferFatPointers() : ModulePass(
ID) {}
2600 bool runOnModule(
Module &M)
override;
2602 void getAnalysisUsage(AnalysisUsage &AU)
const override;
2610 BufferFatPtrToStructTypeMap *TypeMap) {
2611 bool HasFatPointers =
false;
2614 HasFatPointers |= (
I.getType() != TypeMap->remapType(
I.getType()));
2616 for (
const Value *V :
I.operand_values())
2617 HasFatPointers |= (V->getType() != TypeMap->remapType(V->getType()));
2619 return HasFatPointers;
2623 BufferFatPtrToStructTypeMap *TypeMap) {
2624 Type *Ty =
F.getFunctionType();
2625 return Ty != TypeMap->remapType(Ty);
2641 while (!OldF->
empty()) {
2655 CloneMap[&NewArg] = &OldArg;
2656 NewArg.takeName(&OldArg);
2657 Type *OldArgTy = OldArg.getType(), *NewArgTy = NewArg.getType();
2659 NewArg.mutateType(OldArgTy);
2660 OldArg.replaceAllUsesWith(&NewArg);
2661 NewArg.mutateType(NewArgTy);
2665 if (OldArgTy != NewArgTy && !IsIntrinsic)
2668 AttributeFuncs::typeIncompatible(NewArgTy, ArgAttr));
2675 AttributeFuncs::typeIncompatible(NewF->
getReturnType(), RetAttrs));
2677 NewF->
getContext(), OldAttrs.getFnAttrs(), RetAttrs, ArgAttrs));
2685 CloneMap[&BB] = &BB;
2691bool AMDGPULowerBufferFatPointers::run(
Module &M,
const TargetMachine &TM,
2694 const DataLayout &
DL =
M.getDataLayout();
2700 LLVMContext &Ctx =
M.getContext();
2702 BufferFatPtrToStructTypeMap StructTM(
DL);
2703 BufferFatPtrToIntTypeMap IntTM(
DL);
2707 Ctx.
emitError(
"global variables with a buffer fat pointer address "
2708 "space (7) are not supported");
2710 GV.eraseFromParent();
2715 Type *VT = GV.getValueType();
2716 if (VT != StructTM.remapType(VT)) {
2718 Ctx.
emitError(
"global variables that contain buffer fat pointers "
2719 "(address space 7 pointers) are unsupported. Use "
2720 "buffer resource pointers (address space 8) instead");
2722 GV.eraseFromParent();
2738 SmallPtrSet<Constant *, 8> Visited;
2739 SetVector<Constant *> BufferFatPtrConsts;
2740 while (!Worklist.
empty()) {
2742 if (!Visited.
insert(
C).second)
2758 StoreFatPtrsAsIntsAndExpandMemcpyVisitor MemOpsRewrite(&IntTM,
DL,
2760 LegalizeBufferContentTypesVisitor BufferContentsTypeRewrite(
2761 DL,
M.getContext(), &TM);
2765 const TargetTransformInfo *
TTI = GetTTI(
F);
2766 ScalarEvolution *SE = GetSE(
F);
2767 Changed |= MemOpsRewrite.processFunction(
F,
TTI, SE);
2768 if (InterfaceChange || BodyChanges) {
2769 NeedsRemap.
push_back(std::make_pair(&
F, InterfaceChange));
2770 Changed |= BufferContentsTypeRewrite.processFunction(
F, SE);
2773 if (NeedsRemap.
empty())
2780 FatPtrConstMaterializer Materializer(&StructTM, CloneMap);
2782 ValueMapper LowerInFuncs(CloneMap,
RF_None, &StructTM, &Materializer);
2783 for (
auto [
F, InterfaceChange] : NeedsRemap) {
2785 if (InterfaceChange)
2791 LowerInFuncs.remapFunction(*NewF);
2796 if (InterfaceChange) {
2797 F->replaceAllUsesWith(NewF);
2798 F->eraseFromParent();
2806 SplitPtrStructs Splitter(
DL,
M.getContext(), &TM);
2808 Splitter.processFunction(*
F);
2813 F->eraseFromParent();
2817 F->replaceAllUsesWith(*NewF);
2823bool AMDGPULowerBufferFatPointers::runOnModule(
Module &M) {
2824 TargetPassConfig &TPC = getAnalysis<TargetPassConfig>();
2825 const TargetMachine &TM = TPC.
getTM<TargetMachine>();
2826 auto GetTTI = [&](
Function &
F) ->
const TargetTransformInfo * {
2827 if (
F.isDeclaration())
2829 return &getAnalysis<TargetTransformInfoWrapperPass>().getTTI(
F);
2831 auto GetSE = [&](
Function &
F) -> ScalarEvolution * {
2832 if (
F.isDeclaration())
2834 return &getAnalysis<ScalarEvolutionWrapperPass>(
F).getSE();
2836 return run(M, TM, GetTTI, GetSE);
2839char AMDGPULowerBufferFatPointers::ID = 0;
2843void AMDGPULowerBufferFatPointers::getAnalysisUsage(
AnalysisUsage &AU)
const {
2849#define PASS_DESC "Lower buffer fat pointer operations to buffer resources"
2860 return new AMDGPULowerBufferFatPointers();
2867 if (
F.isDeclaration())
2872 if (
F.isDeclaration())
2876 return AMDGPULowerBufferFatPointers().run(M, TM, GetTTI, GetSE)
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
AMDGPU address space definition.
function_ref< const TargetTransformInfo *(Function &)> GetTTIFn
static Function * moveFunctionAdaptingType(Function *OldF, FunctionType *NewTy, ValueToValueMapTy &CloneMap)
Move the body of OldF into a new function, returning it.
static void makeCloneInPraceMap(Function *F, ValueToValueMapTy &CloneMap)
static bool isBufferFatPtrOrVector(Type *Ty)
static bool isSplitFatPtr(Type *Ty)
std::pair< Value *, Value * > PtrParts
static bool hasFatPointerInterface(const Function &F, BufferFatPtrToStructTypeMap *TypeMap)
static bool isRemovablePointerIntrinsic(Intrinsic::ID IID)
Returns true if this intrinsic needs to be removed when it is applied to ptr addrspace(7) values.
static bool containsBufferFatPointers(const Function &F, BufferFatPtrToStructTypeMap *TypeMap)
Returns true if there are values that have a buffer fat pointer in them, which means we'll need to pe...
static Value * rsrcPartRoot(Value *V)
Returns the instruction that defines the resource part of the value V.
static constexpr unsigned BufferOffsetWidth
function_ref< ScalarEvolution *(Function &)> GetSEFn
static bool isBufferFatPtrConst(Constant *C)
static std::pair< Constant *, Constant * > splitLoweredFatBufferConst(Constant *C)
Return the ptr addrspace(8) and i32 (resource and offset parts) in a lowered buffer fat pointer const...
The AMDGPU TargetMachine interface definition for hw codegen targets.
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
Expand Atomic instructions
Atomic ordering constants.
static GCRegistry::Add< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
This file contains the declarations for the subclasses of Constant, which represent the different fla...
AMD GCN specific subclass of TargetSubtarget.
This header defines various interfaces for pass management in LLVM.
Machine Check Debug Module
static bool processFunction(Function &F, NVPTXTargetMachine &TM)
uint64_t IntrinsicInst * II
OptimizedStructLayoutField Field
#define INITIALIZE_PASS_DEPENDENCY(depName)
#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis)
#define INITIALIZE_PASS_BEGIN(passName, arg, name, cfg, analysis)
const SmallVectorImpl< MachineOperand > & Cond
static void visit(BasicBlock &Start, std::function< bool(BasicBlock *)> op)
This file defines generic set operations that may be used on set's of different types,...
This file defines the SmallVector class.
static SymbolRef::Type getType(const Symbol *Sym)
Target-Independent Code Generator Pass Configuration Options pass.
static APInt getAllOnes(unsigned numBits)
Return an APInt of a specified width with all bits set.
LLVM_ABI APInt zext(unsigned width) const
Zero extend to a new width.
static APInt getMaxValue(unsigned numBits)
Gets maximum unsigned value of APInt for specific bit width.
bool ule(const APInt &RHS) const
Unsigned less or equal comparison.
bool sge(const APInt &RHS) const
Signed greater or equal comparison.
This class represents a conversion between pointers from one address space to another.
Value * getPointerOperand()
Gets the pointer operand.
unsigned getSrcAddressSpace() const
Returns the address space of the pointer operand.
unsigned getDestAddressSpace() const
Returns the address space of the result.
PassT::Result & getResult(IRUnitT &IR, ExtraArgTs... ExtraArgs)
Get the result of an analysis pass for a given IR unit.
Represent the analysis usage information of a pass.
AnalysisUsage & addRequired()
This class represents an incoming formal argument to a Function.
An instruction that atomically checks whether a specified value is in a memory location,...
Value * getNewValOperand()
AtomicOrdering getMergedOrdering() const
Returns a single ordering which is at least as strong as both the success and failure orderings for t...
bool isVolatile() const
Return true if this is a cmpxchg from a volatile memory location.
Value * getCompareOperand()
Value * getPointerOperand()
Align getAlign() const
Return the alignment of the memory that is being allocated by the instruction.
SyncScope::ID getSyncScopeID() const
Returns the synchronization scope ID of this cmpxchg instruction.
an instruction that atomically reads a memory location, combines it with another value,...
Align getAlign() const
Return the alignment of the memory that is being allocated by the instruction.
bool isVolatile() const
Return true if this is a RMW on a volatile memory location.
@ USubCond
Subtract only if no unsigned overflow.
@ FMinimum
*p = minimum(old, v) minimum matches the behavior of llvm.minimum.
@ Min
*p = old <signed v ? old : v
@ USubSat
*p = usub.sat(old, v) usub.sat matches the behavior of llvm.usub.sat.
@ FMaximum
*p = maximum(old, v) maximum matches the behavior of llvm.maximum.
@ UIncWrap
Increment one up to a maximum value.
@ Max
*p = old >signed v ? old : v
@ UMin
*p = old <unsigned v ? old : v
@ FMin
*p = minnum(old, v) minnum matches the behavior of llvm.minnum.
@ UMax
*p = old >unsigned v ? old : v
@ FMaximumNum
*p = maximumnum(old, v) maximumnum matches the behavior of llvm.maximumnum.
@ FMax
*p = maxnum(old, v) maxnum matches the behavior of llvm.maxnum.
@ UDecWrap
Decrement one until a minimum value or zero.
@ FMinimumNum
*p = minimumnum(old, v) minimumnum matches the behavior of llvm.minimumnum.
Value * getPointerOperand()
SyncScope::ID getSyncScopeID() const
Returns the synchronization scope ID of this rmw instruction.
AtomicOrdering getOrdering() const
Returns the ordering constraint of this rmw instruction.
This class holds the attributes for a particular argument, parameter, function, or return value.
LLVM_ABI AttributeSet removeAttributes(LLVMContext &C, const AttributeMask &AttrsToRemove) const
Remove the specified attributes from this set.
LLVM Basic Block Representation.
LLVM_ABI void removeFromParent()
Unlink 'this' from the containing function, but do not delete it.
LLVM_ABI void insertInto(Function *Parent, BasicBlock *InsertBefore=nullptr)
Insert unlinked basic block into a function.
void addParamAttr(unsigned ArgNo, Attribute::AttrKind Kind)
Adds the attribute to the indicated argument.
This class represents a function call, abstracting a target machine's calling convention.
static LLVM_ABI Constant * get(StructType *T, ArrayRef< Constant * > V)
static LLVM_ABI Constant * getSplat(ElementCount EC, Constant *Elt)
Return a ConstantVector with the specified constant in each element.
static LLVM_ABI Constant * get(ArrayRef< Constant * > V)
This is an important base class in LLVM.
static LLVM_ABI Constant * getNullValue(Type *Ty)
Constructor to create a '0' constant of arbitrary type.
static LLVM_ABI std::optional< DIExpression * > createFragmentExpression(const DIExpression *Expr, unsigned OffsetInBits, unsigned SizeInBits)
Create a DIExpression to describe one part of an aggregate variable that is fragmented across multipl...
A parsed version of the target data layout string in and methods for querying it.
LLVM_ABI void insertBefore(DbgRecord *InsertBefore)
LLVM_ABI void eraseFromParent()
LLVM_ABI void replaceVariableLocationOp(Value *OldValue, Value *NewValue, bool AllowEmpty=false)
void setExpression(DIExpression *NewExpr)
iterator find(const_arg_type_t< KeyT > Val)
Implements a dense probed hash-table based set.
static LLVM_ABI FixedVectorType * get(Type *ElementType, unsigned NumElts)
This class represents a freeze function that returns random concrete value if an operand is either a ...
static Function * Create(FunctionType *Ty, LinkageTypes Linkage, unsigned AddrSpace, const Twine &N="", Module *M=nullptr)
const BasicBlock & front() const
iterator_range< arg_iterator > args()
AttributeList getAttributes() const
Return the attribute list for this Function.
bool isIntrinsic() const
isIntrinsic - Returns true if the function's name starts with "llvm.".
void setAttributes(AttributeList Attrs)
Set the attribute list for this Function.
LLVMContext & getContext() const
getContext - Return a reference to the LLVMContext associated with this function.
void updateAfterNameChange()
Update internal caches that depend on the function name (such as the intrinsic ID and libcall cache).
Type * getReturnType() const
Returns the type of the ret val.
void copyAttributesFrom(const Function *Src)
copyAttributesFrom - copy all additional attributes (those not needed to create a Function) from the ...
bool hasRelaxedBufferOOBMode() const
bool hasUnalignedBufferAccessEnabled() const
std::optional< unsigned > getBufferResourceNumRecordsWidth() const
Return the width, in bits, of the num_records field of a buffer resource (V#) on this subtarget,...
static GEPNoWrapFlags noUnsignedWrap()
static GEPNoWrapFlags none()
an instruction for type-safe pointer arithmetic to access elements of arrays and structs
LLVM_ABI void copyMetadata(const GlobalObject *Src, unsigned Offset)
Copy metadata from Src, adjusting offsets by Offset.
LinkageTypes getLinkage() const
void setDLLStorageClass(DLLStorageClassTypes C)
unsigned getAddressSpace() const
Module * getParent()
Get the module that this global value is contained inside of...
DLLStorageClassTypes getDLLStorageClass() const
This instruction compares its operands according to the predicate given to the constructor.
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
This instruction inserts a single (scalar) element into a VectorType value.
InstSimplifyFolder - Use InstructionSimplify to fold operations to existing values.
Base class for instruction visitors.
LLVM_ABI Instruction * clone() const
Create a copy of 'this' instruction that is identical in all ways except the following:
LLVM_ABI void setAAMetadata(const AAMDNodes &N)
Sets the AA metadata on this instruction from the AAMDNodes structure.
LLVM_ABI InstListType::iterator eraseFromParent()
This method unlinks 'this' from the containing basic block and deletes it.
MDNode * getMetadata(unsigned KindID) const
Get the metadata of given kind attached to this Instruction.
LLVM_ABI AAMDNodes getAAMetadata() const
Returns the AA metadata for this instruction.
LLVM_ABI const DataLayout & getDataLayout() const
Get the data layout of the module this instruction belongs to.
This class represents a cast from an integer to a pointer.
static LLVM_ABI IntegerType * get(LLVMContext &C, unsigned NumBits)
This static method is the primary way of constructing an IntegerType.
A wrapper class for inspecting calls to intrinsic functions.
This is an important class for using LLVM in a threaded context.
LLVM_ABI void emitError(const Instruction *I, const Twine &ErrorStr)
emitError - Emit an error message to the currently installed error handler with optional location inf...
An instruction for reading from memory.
unsigned getPointerAddressSpace() const
Returns the address space of the pointer operand.
Value * getPointerOperand()
bool isVolatile() const
Return true if this is a load from a volatile memory location.
void setAtomic(AtomicOrdering Ordering, SyncScope::ID SSID=SyncScope::System)
Sets the ordering constraint and the synchronization scope ID of this load instruction.
AtomicOrdering getOrdering() const
Returns the ordering constraint of this load instruction.
Type * getPointerOperandType() const
void setVolatile(bool V)
Specify whether this is a volatile load or not.
SyncScope::ID getSyncScopeID() const
Returns the synchronization scope ID of this load instruction.
Align getAlign() const
Return the alignment of the access that is being performed.
unsigned getDestAddressSpace() const
unsigned getSourceAddressSpace() const
ModulePass class - This class is used to implement unstructured interprocedural optimizations and ana...
A Module instance is used to store all the information related to an LLVM module.
const FunctionListType & getFunctionList() const
Get the Module's list of functions (constant).
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.
This class represents a cast from a pointer to an address (non-capturing ptrtoint).
Value * getPointerOperand()
Gets the pointer operand.
This class represents a cast from a pointer to an integer.
Value * getPointerOperand()
Gets the pointer operand.
Analysis pass that exposes the ScalarEvolution for a function.
The main scalar evolution driver.
LLVM_ABI bool isKnownNonNegative(const SCEV *S)
Test if the given expression is known to be non-negative.
LLVM_ABI bool isKnownNonPositive(const SCEV *S)
Test if the given expression is known to be non-positive.
LLVM_ABI const SCEV * getConstant(ConstantInt *V)
LLVM_ABI const SCEV * getSCEV(Value *V)
Return a SCEV expression for the full generality of the specified expression.
LLVM_ABI const SCEV * getMinusSCEV(SCEVUse LHS, SCEVUse RHS, SCEV::NoWrapFlags Flags=SCEV::FlagAnyWrap, unsigned Depth=0)
Return LHS-RHS.
LLVM_ABI bool isSCEVable(Type *Ty) const
Test if values of the given type are analyzable within the SCEV framework.
APInt getSignedRangeMin(const SCEV *S)
Determine the min of the signed range for a particular SCEV.
LLVM_ABI const SCEV * getNoopOrZeroExtend(const SCEV *V, Type *Ty)
Return a SCEV corresponding to a conversion of the input value to the specified type.
LLVM_ABI const SCEV * getPointerBase(const SCEV *V)
Transitively follow the chain of pointer-type operands until reaching a SCEV that does not have a sin...
APInt getUnsignedRangeMax(const SCEV *S)
Determine the max of the unsigned range for a particular SCEV.
LLVM_ABI const SCEV * getAddExpr(SmallVectorImpl< SCEVUse > &Ops, SCEV::NoWrapFlags Flags=SCEV::FlagAnyWrap, unsigned Depth=0)
Get a canonical add expression, or something simpler if possible.
LLVM_ABI const SCEV * getTruncateOrZeroExtend(const SCEV *V, Type *Ty, unsigned Depth=0)
Return a SCEV corresponding to a conversion of the input value to the specified type.
This class represents the LLVM 'select' instruction.
ArrayRef< value_type > getArrayRef() const
bool insert(const value_type &X)
Insert a new element into the SetVector.
This instruction constructs a fixed permutation of two input vectors.
A templated base class for SmallPtrSet which provides the typesafe interface that is common across al...
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
An instruction for storing to memory.
Value * getValueOperand()
Value * getPointerOperand()
MutableArrayRef< TypeSize > getMemberOffsets()
static LLVM_ABI StructType * get(LLVMContext &Context, ArrayRef< Type * > Elements, bool isPacked=false)
This static method is the primary way to create a literal StructType.
static LLVM_ABI StructType * create(LLVMContext &Context, StringRef Name)
This creates an identified struct.
bool isLiteral() const
Return true if this type is uniqued by structural equivalence, false if it is a struct definition.
Type * getElementType(unsigned N) const
Analysis pass providing the TargetTransformInfo.
Primary interface to the complete machine description for the target machine.
const STC & getSubtarget(const Function &F) const
This method returns a pointer to the specified type of TargetSubtargetInfo.
Target-Independent Code Generator Pass Configuration Options.
TMC & getTM() const
Get the right type of TargetMachine for this target.
The instances of the Type class are immutable: once they are created, they are never changed.
LLVM_ABI unsigned getIntegerBitWidth() const
bool isVectorTy() const
True if this is an instance of VectorType.
Type * getArrayElementType() const
ArrayRef< Type * > subtypes() const
bool isSingleValueType() const
Return true if the type is a valid type for a register in codegen.
unsigned getNumContainedTypes() const
Return the number of types in the derived type.
Type * getScalarType() const
If this is a vector type, return the element type, otherwise return 'this'.
LLVM_ABI Type * getWithNewBitWidth(unsigned NewBitWidth) const
Given an integer or vector type, change the lane bitwidth to NewBitwidth, whilst keeping the old numb...
LLVM_ABI Type * getWithNewType(Type *EltTy) const
Given vector type, change the element type, whilst keeping the old number of elements.
LLVMContext & getContext() const
Return the LLVMContext in which this type was uniqued.
LLVM_ABI unsigned getScalarSizeInBits() const LLVM_READONLY
If this is a vector type, return the getPrimitiveSizeInBits value for the element type.
bool isIntegerTy() const
True if this is an instance of IntegerType.
Type * getContainedType(unsigned i) const
This method is used to implement the type iterator (defined at the end of the file).
static LLVM_ABI UndefValue * get(Type *T)
Static factory methods - Return an 'undef' object of the specified type.
A Use represents the edge between a Value definition and its users.
void setOperand(unsigned i, Value *Val)
Value * getOperand(unsigned i) const
This is a class that can be implemented by clients to remap types when cloning constants and instruct...
size_type count(const KeyT &Val) const
Return 1 if the specified key is in the map, 0 otherwise.
iterator find(const KeyT &Val)
std::pair< iterator, bool > insert(const std::pair< KeyT, ValueT > &KV)
LLVM_ABI Constant * mapConstant(const Constant &C)
LLVM_ABI Value * mapValue(const Value &V)
LLVM Value Representation.
Type * getType() const
All values are typed, get the type of this value.
LLVM_ABI void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
LLVMContext & getContext() const
All values hold a context through their type.
LLVM_ABI StringRef getName() const
Return a constant reference to the value's name.
LLVM_ABI void takeName(Value *V)
Transfer the name from V to this value.
std::pair< iterator, bool > insert(const ValueT &V)
bool contains(const_arg_type_t< ValueT > V) const
Check if the set contains the given element.
constexpr bool isKnownMultipleOf(ScalarTy RHS) const
This function tells the caller whether the element count is known at compile time to be a multiple of...
constexpr ScalarTy getFixedValue() const
constexpr ScalarTy getKnownMinValue() const
Returns the minimum value this quantity can represent.
An efficient, type-erasing, non-owning reference to a callable.
self_iterator getIterator()
iterator insertAfter(iterator where, pointer New)
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
@ BUFFER_FAT_POINTER
Address space for 160-bit buffer fat pointers.
@ BUFFER_RESOURCE
Address space for 128-bit buffer resources.
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.
LLVM_ABI std::optional< Function * > remangleIntrinsicFunction(Function *F)
bool match(Val *V, const Pattern &P)
is_zero m_Zero()
Match any null constant or a vector with all elements equal to 0.
SmallVector< DbgVariableRecord * > getDVRAssignmentMarkers(const Instruction *Inst)
Return a range of dbg_assign records for which Inst performs the assignment they encode.
DXILDebugInfoMap run(Module &M)
friend class Instruction
Iterator for Instructions in a `BasicBlock.
This is an optimization pass for GlobalISel generic memory operations.
detail::zippy< detail::zip_shortest, T, U, Args... > zip(T &&t, U &&u, Args &&...args)
zip iterator for two or more iteratable types.
LLVM_ABI void findDbgValues(Value *V, SmallVectorImpl< DbgVariableRecord * > &DbgVariableRecords)
Finds the dbg.values describing a value.
ModulePass * createAMDGPULowerBufferFatPointersPass()
auto enumerate(FirstRange &&First, RestRanges &&...Rest)
Given two or more input ranges, returns a new range whose values are tuples (A, B,...
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
LLVM_ABI void copyMetadataForLoad(LoadInst &Dest, const LoadInst &Source)
Copy the metadata from the source instruction to the destination (the replacement for the source inst...
bool set_is_subset(const S1Ty &S1, const S2Ty &S2)
set_is_subset(A, B) - Return true iff A in B
iterator_range< early_inc_iterator_impl< detail::IterOfRange< RangeT > > > make_early_inc_range(RangeT &&Range)
Make a range that does early increment to allow mutation of the underlying range without disrupting i...
InnerAnalysisManagerProxy< FunctionAnalysisManager, Module > FunctionAnalysisManagerModuleProxy
Provide the FunctionAnalysisManager to Module proxy.
constexpr bool isPowerOf2_64(uint64_t Value)
Return true if the argument is a power of two > 0 (64 bit edition.)
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Value
auto dyn_cast_or_null(const Y &Val)
LLVM_ABI bool convertUsersOfConstantsToInstructions(ArrayRef< Constant * > Consts, Function *RestrictToFunc=nullptr, bool RemoveDeadConstants=true, bool IncludeSelf=false)
Replace constant expressions users of the given constants with instructions.
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
LLVM_ABI Value * emitGEPOffset(IRBuilderBase *Builder, const DataLayout &DL, User *GEP, bool NoAssumptions=false)
Given a getelementptr instruction/constantexpr, emit the code necessary to compute the offset from th...
constexpr bool isPowerOf2_32(uint32_t Value)
Return true if the argument is a power of two > 0.
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
SmallVector< ValueTypeFromRangeType< R >, Size > to_vector(R &&Range)
Given a range of type R, iterate the entire range and return a SmallVector with elements of the vecto...
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
char & AMDGPULowerBufferFatPointersID
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
MutableArrayRef(T &OneElt) -> MutableArrayRef< T >
AtomicOrdering
Atomic ordering for LLVM's memory model.
constexpr T divideCeil(U Numerator, V Denominator)
Returns the integer ceil(Numerator / Denominator).
IRBuilder(LLVMContext &, FolderTy, InserterTy, MDNode *, ArrayRef< OperandBundleDef >) -> IRBuilder< FolderTy, InserterTy >
DWARFExpression::Operation Op
S1Ty set_difference(const S1Ty &S1, const S2Ty &S2)
set_difference(A, B) - Return A - B
ArrayRef(const T &OneElt) -> ArrayRef< T >
ValueMap< const Value *, WeakTrackingVH > ValueToValueMapTy
LLVM_ABI void expandMemSetAsLoop(MemSetInst *MemSet, const TargetTransformInfo *TTI=nullptr)
Expand MemSet as a loop.
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
LLVM_ABI void expandMemSetPatternAsLoop(MemSetPatternInst *MemSet, const TargetTransformInfo *TTI=nullptr)
Expand MemSetPattern as a loop.
iterator_range< pointer_iterator< WrappedIteratorT > > make_pointer_range(RangeT &&Range)
Align commonAlignment(Align A, uint64_t Offset)
Returns the alignment that satisfies both alignments.
LLVM_ABI void expandMemCpyAsLoop(MemCpyInst *MemCpy, const TargetTransformInfo &TTI, ScalarEvolution *SE=nullptr)
Expand MemCpy as a loop. MemCpy is not deleted.
AnalysisManager< Module > ModuleAnalysisManager
Convenience typedef for the Module analysis manager.
LLVM_ABI void reportFatalUsageError(Error Err)
Report a fatal error that does not indicate a bug in LLVM.
LLVM_ABI AAMDNodes adjustForAccess(unsigned AccessSize)
Create a new AAMDNode for accessing AccessSize bytes of this AAMDNode.
PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM)
This struct is a compact representation of a valid (non-zero power of two) alignment.