243#include "llvm/IR/IntrinsicsAMDGPU.h"
261#define DEBUG_TYPE "amdgpu-lower-buffer-fat-pointers"
286 Type *remapType(
Type *SrcTy)
override;
287 void clear() { Map.clear(); }
293class BufferFatPtrToIntTypeMap :
public BufferFatPtrTypeLoweringBase {
294 using BufferFatPtrTypeLoweringBase::BufferFatPtrTypeLoweringBase;
304class BufferFatPtrToStructTypeMap :
public BufferFatPtrTypeLoweringBase {
305 using BufferFatPtrTypeLoweringBase::BufferFatPtrTypeLoweringBase;
314Type *BufferFatPtrTypeLoweringBase::remapTypeImpl(
Type *Ty) {
320 return *
Entry = remapScalar(PT);
326 return *
Entry = remapVector(VT);
334 bool IsUniqued = !TyAsStruct || TyAsStruct->
isLiteral();
343 Type *NewElem = remapTypeImpl(OldElem);
344 ElementTypes[
I] = NewElem;
345 Changed |= (OldElem != NewElem);
353 return *
Entry = ArrayType::get(ElementTypes[0], ArrTy->getNumElements());
355 return *
Entry = FunctionType::get(ElementTypes[0],
365 SmallString<16>
Name(STy->getName());
373Type *BufferFatPtrTypeLoweringBase::remapType(
Type *SrcTy) {
374 return remapTypeImpl(SrcTy);
377Type *BufferFatPtrToStructTypeMap::remapScalar(PointerType *PT) {
378 LLVMContext &Ctx = PT->getContext();
383Type *BufferFatPtrToStructTypeMap::remapVector(VectorType *VT) {
384 ElementCount
EC = VT->getElementCount();
385 LLVMContext &Ctx = VT->getContext();
404 if (!ST->isLiteral() || ST->getNumElements() != 2)
410 return MaybeRsrc && MaybeOff &&
419 return isBufferFatPtrOrVector(U.get()->getType());
432class StoreFatPtrsAsIntsAndExpandMemcpyVisitor
433 :
public InstVisitor<StoreFatPtrsAsIntsAndExpandMemcpyVisitor, bool> {
434 BufferFatPtrToIntTypeMap *TypeMap;
438 const DataLayout &
DL;
441 const TargetTransformInfo *
TTI;
450 function_ref<
void(
Type *LeafTy,
Type *IntLeafTy, ArrayRef<unsigned> Idxs,
455 StoreFatPtrsAsIntsAndExpandMemcpyVisitor(BufferFatPtrToIntTypeMap *TypeMap,
457 : TypeMap(TypeMap), IRB(
M, InstSimplifyFolder(
M.getDataLayout())),
458 DL(
M.getDataLayout()) {}
460 ScalarEvolution *SE);
462 bool visitInstruction(Instruction &
I) {
return false; }
463 bool visitAllocaInst(AllocaInst &
I);
464 bool visitLoadInst(LoadInst &LI);
465 bool visitStoreInst(StoreInst &SI);
466 bool visitGetElementPtrInst(GetElementPtrInst &
I);
468 bool visitMemCpyInst(MemCpyInst &MCI);
469 bool visitMemMoveInst(MemMoveInst &MMI);
470 bool visitMemSetInst(MemSetInst &MSI);
471 bool visitMemSetPatternInst(MemSetPatternInst &MSPI);
475Value *StoreFatPtrsAsIntsAndExpandMemcpyVisitor::applyOffset(
Value *Ptr,
478 return IRB.CreatePtrAddWithUnsignedOffset(
483void StoreFatPtrsAsIntsAndExpandMemcpyVisitor::forEachAggLeaf(
486 function_ref<
void(
Type *LeafTy,
Type *IntLeafTy, ArrayRef<unsigned> Idxs,
489 Type *IntTy = TypeMap->remapType(Ty);
492 if (
DL.getTypeStoreSize(Ty) != 0)
493 Visit(Ty, IntTy, AggIdxs,
Off, Name);
496 auto Recurse = [&](
unsigned I,
Type *ElemTy,
uint64_t ElemOff) {
498 forEachAggLeaf(ElemTy, AggIdxs,
Off + ElemOff, Name +
"." + Twine(
I),
503 const StructLayout *Layout =
DL.getStructLayout(ST);
504 for (
auto [
I, ElemTy, ElemOff] :
506 Recurse(
I, ElemTy, ElemOff.getFixedValue());
510 Type *ElemTy = AT->getElementType();
511 uint64_t Stride =
DL.getTypeAllocSize(ElemTy).getFixedValue();
513 Recurse(
I, ElemTy,
I * Stride);
516bool StoreFatPtrsAsIntsAndExpandMemcpyVisitor::processFunction(
517 Function &
F,
const TargetTransformInfo *
TTI, ScalarEvolution *SE) {
538bool StoreFatPtrsAsIntsAndExpandMemcpyVisitor::visitAllocaInst(AllocaInst &
I) {
539 Type *Ty =
I.getAllocatedType();
540 Type *NewTy = TypeMap->remapType(Ty);
545 TypeSize AllocSize =
DL.getTypeAllocSize(Ty);
546 if (AllocSize.
isFixed() &&
DL.getTypeAllocSize(NewTy) != AllocSize)
547 NewTy = ArrayType::get(IRB.getInt8Ty(), AllocSize.
getFixedValue());
548 I.setAllocatedType(NewTy);
552bool StoreFatPtrsAsIntsAndExpandMemcpyVisitor::visitGetElementPtrInst(
553 GetElementPtrInst &
I) {
554 Type *Ty =
I.getSourceElementType();
555 if (Ty == TypeMap->remapType(Ty))
559 IRB.SetInsertPoint(&
I);
561 Value *NewGEP = IRB.CreatePtrAdd(
I.getPointerOperand(),
Off,
I.getName(),
563 I.replaceAllUsesWith(NewGEP);
568bool StoreFatPtrsAsIntsAndExpandMemcpyVisitor::visitLoadInst(LoadInst &LI) {
570 Type *IntTy = TypeMap->remapType(Ty);
574 IRB.SetInsertPoint(&LI);
580 SmallVector<unsigned> AggIdxs;
583 [&](
Type *LeafTy,
Type *IntLeafTy, ArrayRef<unsigned> Idxs,
585 Value *Ptr = applyOffset(LI.getPointerOperand(), Off);
586 LoadInst *NewLI = IRB.CreateAlignedLoad(
587 IntLeafTy, Ptr, commonAlignment(LI.getAlign(), Off), Name);
588 NewLI->setVolatile(LI.isVolatile());
589 copyMetadataForLoad(*NewLI, LI);
590 NewLI->setAAMetadata(AATags.adjustForAccess(Off, IntLeafTy, DL));
592 if (LeafTy != IntLeafTy)
593 V = IRB.CreateIntToPtr(NewLI, LeafTy, Name +
".ptr");
594 Agg = IRB.CreateInsertValue(Agg, V, Idxs, Name +
".agg");
601 NLI->mutateType(IntTy);
602 NLI = IRB.Insert(NLI);
605 Value *CastBack = IRB.CreateIntToPtr(NLI, Ty, NLI->getName() +
".ptr");
611bool StoreFatPtrsAsIntsAndExpandMemcpyVisitor::visitStoreInst(StoreInst &SI) {
613 Type *Ty =
V->getType();
614 Type *IntTy = TypeMap->remapType(Ty);
618 IRB.SetInsertPoint(&SI);
622 AAMDNodes AATags =
SI.getAAMetadata();
623 SmallVector<unsigned> AggIdxs;
625 Ty, AggIdxs, 0,
V->getName(),
626 [&](
Type *LeafTy,
Type *IntLeafTy, ArrayRef<unsigned> Idxs,
628 Value *Leaf = IRB.CreateExtractValue(V, Idxs, Name);
629 if (LeafTy != IntLeafTy)
630 Leaf = IRB.CreatePtrToInt(Leaf, IntLeafTy, Name +
".int");
631 auto *NewSI = cast<StoreInst>(SI.clone());
632 NewSI->setAlignment(commonAlignment(SI.getAlign(), Off));
633 NewSI->setOperand(0, Leaf);
634 NewSI->setOperand(1, applyOffset(SI.getPointerOperand(), Off));
636 NewSI->setMetadata(LLVMContext::MD_DIAssignID, nullptr);
638 NewSI->setAAMetadata(AATags.adjustForAccess(Off, IntLeafTy, DL));
640 SI.eraseFromParent();
643 Value *IntV = IRB.CreatePtrToInt(
V, IntTy,
V->getName() +
".int");
647 SI.setOperand(0, IntV);
651bool StoreFatPtrsAsIntsAndExpandMemcpyVisitor::visitMemCpyInst(
663bool StoreFatPtrsAsIntsAndExpandMemcpyVisitor::visitMemMoveInst(
669 "memmove() on buffer descriptors is not implemented because pointer "
670 "comparison on buffer descriptors isn't implemented\n");
673bool StoreFatPtrsAsIntsAndExpandMemcpyVisitor::visitMemSetInst(
682bool StoreFatPtrsAsIntsAndExpandMemcpyVisitor::visitMemSetPatternInst(
683 MemSetPatternInst &MSPI) {
712class LegalizeBufferContentTypesVisitor
713 :
public InstVisitor<LegalizeBufferContentTypesVisitor, bool> {
714 friend class InstVisitor<LegalizeBufferContentTypesVisitor, bool>;
718 const DataLayout &
DL;
720 ScalarEvolution *SE =
nullptr;
730 const TargetMachine *TM;
731 const GCNSubtarget *ST =
nullptr;
735 Type *scalarArrayTypeAsVector(
Type *MaybeArrayType);
741 struct OobProperties {
743 bool NoWrapFromMax =
false;
745 bool NoPartialOOB =
false;
747 OobProperties() =
delete;
749 OobProperties(
bool NoWrapFromMax,
bool NoPartialOOB)
750 : NoWrapFromMax(NoWrapFromMax), NoPartialOOB(NoPartialOOB) {}
761 Value *makeLegalNonAggregate(
Value *
V,
Type *TargetType,
const Twine &Name);
762 Value *makeIllegalNonAggregate(
Value *
V,
Type *OrigType,
const Twine &Name);
776 SmallVectorImpl<VecSlice> &Slices);
778 Value *extractSlice(
Value *Vec, VecSlice S,
const Twine &Name);
779 Value *insertSlice(
Value *Whole,
Value *Part, VecSlice S,
const Twine &Name);
789 Type *intrinsicTypeFor(
Type *LegalType);
791 bool visitLoadImpl(LoadInst &OrigLI,
Type *PartType,
792 SmallVectorImpl<uint32_t> &AggIdxs,
uint64_t AggByteOffset,
793 Value *&Result,
const Twine &Name);
795 std::pair<bool, bool> visitStoreImpl(StoreInst &OrigSI,
Type *PartType,
796 SmallVectorImpl<uint32_t> &AggIdxs,
800 bool visitInstruction(Instruction &
I) {
return false; }
801 bool visitLoadInst(LoadInst &LI);
802 bool visitStoreInst(StoreInst &SI);
805 bool visitIntrinsicInst(IntrinsicInst &
II);
806 bool visitAddrSpaceCastInst(AddrSpaceCastInst &ASCI);
809 LegalizeBufferContentTypesVisitor(
Module &M,
const TargetMachine *TM)
810 : IRB(
M, InstSimplifyFolder(
M.getDataLayout())),
DL(
M.getDataLayout()),
816Type *LegalizeBufferContentTypesVisitor::scalarArrayTypeAsVector(
Type *
T) {
820 Type *ET = AT->getElementType();
823 "should have recursed");
824 if (!
DL.typeSizeEqualsStoreSize(AT))
826 "loading padded arrays from buffer fat pinters should have recursed");
830Value *LegalizeBufferContentTypesVisitor::arrayToVector(
Value *
V,
835 unsigned EC = VT->getNumElements();
836 for (
auto I : iota_range<unsigned>(0, EC,
false)) {
837 Value *Elem = IRB.CreateExtractValue(
V,
I, Name +
".elem." + Twine(
I));
838 VectorRes = IRB.CreateInsertElement(VectorRes, Elem,
I,
839 Name +
".as.vec." + Twine(
I));
844Value *LegalizeBufferContentTypesVisitor::vectorToArray(
Value *
V,
849 unsigned EC = AT->getNumElements();
850 for (
auto I : iota_range<unsigned>(0, EC,
false)) {
851 Value *Elem = IRB.CreateExtractElement(
V,
I, Name +
".elem." + Twine(
I));
852 ArrayRes = IRB.CreateInsertValue(ArrayRes, Elem,
I,
853 Name +
".as.array." + Twine(
I));
858LegalizeBufferContentTypesVisitor::OobProperties
859LegalizeBufferContentTypesVisitor::analyzeOobProperties(
Value *Ptr,
Type *Ty,
861 OobProperties
Result(
false,
false);
864 return OobProperties(
true,
true);
870 const SCEV *PtrOp = SE->
getSCEV(Ptr);
876 Value *PtrBaseVal = PtrBase->getValue();
883 auto NumRecordsIfKnown = ZeroBasePointerToNumRecords.
find(PtrBaseVal);
884 if (NumRecordsIfKnown == ZeroBasePointerToNumRecords.
end())
887 unsigned TypeSize =
DL.getTypeStoreSize(Ty).getKnownMinValue();
892 Result.NoWrapFromMax =
true;
896 if (!NumRecordsIfKnown->second)
898 const SCEV *NumRecords = SE->
getSCEV(NumRecordsIfKnown->second);
901 std::optional<unsigned> MaybeNumRecordsWidth =
903 if (!MaybeNumRecordsWidth)
905 unsigned NumRecordsWidth = *MaybeNumRecordsWidth;
906 Type *NumRecordsTy = IRB.getIntNTy(NumRecordsWidth);
908 Type *CompareTy = IRB.getInt64Ty();
916 Result.NoPartialOOB =
true;
918 const SCEV *BoundsDiff =
923 Result.NoPartialOOB =
true;
927Type *LegalizeBufferContentTypesVisitor::legalNonAggregateForMemOp(
929 TypeSize
Size =
DL.getTypeStoreSizeInBits(
T);
931 if (!
DL.typeSizeEqualsStoreSize(
T))
932 T = IRB.getIntNTy(
Size.getFixedValue());
939 unsigned ElemSize =
DL.getTypeSizeInBits(ElemTy).getFixedValue();
940 if (
isPowerOf2_32(ElemSize) && ElemSize >= 16 && ElemSize <= MaxWidth) {
946 Type *BestVectorElemType =
nullptr;
947 if (
Size.isKnownMultipleOf(32) && MaxWidth >= 32)
948 BestVectorElemType = IRB.getInt32Ty();
949 else if (
Size.isKnownMultipleOf(16) && MaxWidth >= 16)
950 BestVectorElemType = IRB.getInt16Ty();
952 BestVectorElemType = IRB.getInt8Ty();
953 unsigned NumCastElems =
955 if (NumCastElems == 1)
956 return BestVectorElemType;
960Value *LegalizeBufferContentTypesVisitor::makeLegalNonAggregate(
961 Value *
V,
Type *TargetType,
const Twine &Name) {
962 Type *SourceType =
V->getType();
963 TypeSize SourceSize =
DL.getTypeSizeInBits(SourceType);
964 TypeSize TargetSize =
DL.getTypeSizeInBits(TargetType);
965 if (SourceSize != TargetSize) {
968 Value *AsScalar = IRB.CreateBitCast(
V, ShortScalarTy, Name +
".as.scalar");
969 Value *Zext = IRB.CreateZExt(AsScalar, ByteScalarTy, Name +
".zext");
971 SourceType = ByteScalarTy;
973 return IRB.CreateBitCast(
V, TargetType, Name +
".legal");
976Value *LegalizeBufferContentTypesVisitor::makeIllegalNonAggregate(
977 Value *
V,
Type *OrigType,
const Twine &Name) {
978 Type *LegalType =
V->getType();
979 TypeSize LegalSize =
DL.getTypeSizeInBits(LegalType);
980 TypeSize OrigSize =
DL.getTypeSizeInBits(OrigType);
981 if (LegalSize != OrigSize) {
984 Value *AsScalar = IRB.CreateBitCast(
V, ByteScalarTy, Name +
".bytes.cast");
985 Value *Trunc = IRB.CreateTrunc(AsScalar, ShortScalarTy, Name +
".trunc");
986 return IRB.CreateBitCast(Trunc, OrigType, Name +
".orig");
988 return IRB.CreateBitCast(
V, OrigType, Name +
".real.ty");
991Type *LegalizeBufferContentTypesVisitor::intrinsicTypeFor(
Type *LegalType) {
995 Type *ET = VT->getElementType();
998 if (VT->getNumElements() == 1)
1000 if (
DL.getTypeSizeInBits(LegalType) == 96 &&
DL.getTypeSizeInBits(ET) < 32)
1003 switch (VT->getNumElements()) {
1007 return IRB.getInt8Ty();
1009 return IRB.getInt16Ty();
1011 return IRB.getInt32Ty();
1021void LegalizeBufferContentTypesVisitor::getVecSlices(
1022 Type *
T,
uint64_t MaxWidth, SmallVectorImpl<VecSlice> &Slices) {
1029 DL.getTypeSizeInBits(VT->getElementType()).getFixedValue();
1031 uint64_t ElemsPer4Words = 128 / ElemBitWidth;
1032 uint64_t ElemsPer2Words = ElemsPer4Words / 2;
1033 uint64_t ElemsPerWord = ElemsPer2Words / 2;
1034 uint64_t ElemsPerShort = ElemsPerWord / 2;
1035 uint64_t ElemsPerByte = ElemsPerShort / 2;
1039 uint64_t ElemsPer3Words = ElemsPerWord * 3;
1041 uint64_t TotalElems = VT->getNumElements();
1043 auto TrySlice = [&](
unsigned MaybeLen,
unsigned Width) {
1044 if (MaybeLen > 0 && Width <= MaxWidth && Index + MaybeLen <= TotalElems) {
1045 VecSlice Slice{
Index, MaybeLen};
1052 while (Index < TotalElems) {
1053 TrySlice(ElemsPer4Words, 128) || TrySlice(ElemsPer3Words, 96) ||
1054 TrySlice(ElemsPer2Words, 64) || TrySlice(ElemsPerWord, 32) ||
1055 TrySlice(ElemsPerShort, 16) || TrySlice(ElemsPerByte, 8);
1059Value *LegalizeBufferContentTypesVisitor::extractSlice(
Value *Vec, VecSlice S,
1060 const Twine &Name) {
1064 if (S.Length == VecVT->getNumElements() && S.Index == 0)
1067 return IRB.CreateExtractElement(Vec, S.Index,
1068 Name +
".slice." + Twine(S.Index));
1070 llvm::iota_range<int>(S.Index, S.Index + S.Length,
false));
1071 return IRB.CreateShuffleVector(Vec, Mask, Name +
".slice." + Twine(S.Index));
1074Value *LegalizeBufferContentTypesVisitor::insertSlice(
Value *Whole,
Value *Part,
1076 const Twine &Name) {
1080 if (S.Length == WholeVT->getNumElements() && S.Index == 0)
1082 if (S.Length == 1) {
1083 return IRB.CreateInsertElement(Whole, Part, S.Index,
1084 Name +
".slice." + Twine(S.Index));
1089 SmallVector<int> ExtPartMask(NumElems, -1);
1094 Value *ExtPart = IRB.CreateShuffleVector(Part, ExtPartMask,
1095 Name +
".ext." + Twine(S.Index));
1097 SmallVector<int>
Mask =
1102 return IRB.CreateShuffleVector(Whole, ExtPart, Mask,
1103 Name +
".parts." + Twine(S.Index));
1106bool LegalizeBufferContentTypesVisitor::visitLoadImpl(
1107 LoadInst &OrigLI,
Type *PartType, SmallVectorImpl<uint32_t> &AggIdxs,
1110 const StructLayout *Layout =
DL.getStructLayout(ST);
1112 for (
auto [
I, ElemTy,
Offset] :
1115 Changed |= visitLoadImpl(OrigLI, ElemTy, AggIdxs,
1116 AggByteOff +
Offset.getFixedValue(), Result,
1117 Name +
"." + Twine(
I));
1123 Type *ElemTy = AT->getElementType();
1126 TypeSize ElemAllocSize =
DL.getTypeAllocSize(ElemTy);
1128 for (
auto I : llvm::iota_range<uint32_t>(0, AT->getNumElements(),
1131 Changed |= visitLoadImpl(OrigLI, ElemTy, AggIdxs,
1133 Result, Name + Twine(
I));
1143 Type *ArrayAsVecType = scalarArrayTypeAsVector(PartType);
1144 OobProperties OobProps =
1147 DL, ArrayAsVecType, PartAlign, OobProps.NoWrapFromMax,
1148 OobProps.NoPartialOOB);
1149 Type *LegalType = legalNonAggregateForMemOp(ArrayAsVecType, MaxWidth);
1152 getVecSlices(LegalType, MaxWidth, Slices);
1153 bool HasSlices = Slices.
size() > 1;
1154 bool IsAggPart = !AggIdxs.
empty();
1156 if (!HasSlices && !IsAggPart) {
1157 Type *LoadableType = intrinsicTypeFor(LegalType);
1158 if (LoadableType == PartType)
1161 IRB.SetInsertPoint(&OrigLI);
1163 NLI->mutateType(LoadableType);
1164 NLI = IRB.Insert(NLI);
1165 NLI->setName(Name +
".loadable");
1167 LoadsRes = IRB.CreateBitCast(NLI, LegalType, Name +
".from.loadable");
1169 IRB.SetInsertPoint(&OrigLI);
1177 unsigned ElemBytes =
DL.getTypeStoreSize(ElemType);
1179 if (IsAggPart && Slices.
empty())
1181 for (VecSlice S : Slices) {
1184 int64_t ByteOffset = AggByteOff + S.Index * ElemBytes;
1186 Value *NewPtr = IRB.CreateGEP(
1188 OrigPtr->
getName() +
".off.ptr." + Twine(ByteOffset),
1191 Type *LoadableType = intrinsicTypeFor(SliceType);
1192 LoadInst *NewLI = IRB.CreateAlignedLoad(
1194 Name +
".off." + Twine(ByteOffset));
1200 Value *
Loaded = IRB.CreateBitCast(NewLI, SliceType,
1201 NewLI->
getName() +
".from.loadable");
1202 LoadsRes = insertSlice(LoadsRes, Loaded, S, Name);
1205 if (LegalType != ArrayAsVecType)
1206 LoadsRes = makeIllegalNonAggregate(LoadsRes, ArrayAsVecType, Name);
1207 if (ArrayAsVecType != PartType)
1208 LoadsRes = vectorToArray(LoadsRes, PartType, Name);
1211 Result = IRB.CreateInsertValue(Result, LoadsRes, AggIdxs, Name);
1217bool LegalizeBufferContentTypesVisitor::visitLoadInst(LoadInst &LI) {
1221 SmallVector<uint32_t> AggIdxs;
1224 bool Changed = visitLoadImpl(LI, OrigType, AggIdxs, 0, Result, LI.
getName());
1233std::pair<bool, bool> LegalizeBufferContentTypesVisitor::visitStoreImpl(
1234 StoreInst &OrigSI,
Type *PartType, SmallVectorImpl<uint32_t> &AggIdxs,
1235 uint64_t AggByteOff,
const Twine &Name) {
1237 const StructLayout *Layout =
DL.getStructLayout(ST);
1239 for (
auto [
I, ElemTy,
Offset] :
1242 Changed |= visitStoreImpl(OrigSI, ElemTy, AggIdxs,
1243 AggByteOff +
Offset.getFixedValue(),
1244 Name +
"." + Twine(
I))
1248 return std::make_pair(
Changed,
false);
1251 Type *ElemTy = AT->getElementType();
1254 TypeSize ElemAllocSize =
DL.getTypeAllocSize(ElemTy);
1256 for (
auto I : llvm::iota_range<uint32_t>(0, AT->getNumElements(),
1260 visitStoreImpl(OrigSI, ElemTy, AggIdxs,
1266 return std::make_pair(
Changed,
false);
1271 Value *NewData = OrigData;
1273 bool IsAggPart = !AggIdxs.
empty();
1275 NewData = IRB.CreateExtractValue(NewData, AggIdxs, Name);
1277 Type *ArrayAsVecType = scalarArrayTypeAsVector(PartType);
1278 if (ArrayAsVecType != PartType) {
1279 NewData = arrayToVector(NewData, ArrayAsVecType, Name);
1283 OobProperties OobProps =
1286 DL, ArrayAsVecType, PartAlign, OobProps.NoWrapFromMax,
1287 OobProps.NoPartialOOB);
1288 Type *LegalType = legalNonAggregateForMemOp(ArrayAsVecType, MaxWidth);
1289 if (LegalType != ArrayAsVecType) {
1290 NewData = makeLegalNonAggregate(NewData, LegalType, Name);
1294 getVecSlices(LegalType, MaxWidth, Slices);
1295 bool NeedToSplit = Slices.
size() > 1 || IsAggPart;
1297 Type *StorableType = intrinsicTypeFor(LegalType);
1298 if (StorableType == PartType)
1299 return std::make_pair(
false,
false);
1300 NewData = IRB.CreateBitCast(NewData, StorableType, Name +
".storable");
1302 return std::make_pair(
true,
true);
1307 if (IsAggPart && Slices.
empty())
1309 unsigned ElemBytes =
DL.getTypeStoreSize(ElemType);
1311 for (VecSlice S : Slices) {
1314 int64_t ByteOffset = AggByteOff + S.Index * ElemBytes;
1315 Value *NewPtr = IRB.CreateGEP(
1316 IRB.getInt8Ty(), OrigPtr, IRB.getInt32(ByteOffset),
1317 OrigPtr->
getName() +
".part." + Twine(S.Index),
1320 Value *DataSlice = extractSlice(NewData, S, Name);
1321 Type *StorableType = intrinsicTypeFor(SliceType);
1322 DataSlice = IRB.CreateBitCast(DataSlice, StorableType,
1323 DataSlice->
getName() +
".storable");
1327 NewSI->setOperand(0, DataSlice);
1328 NewSI->setOperand(1, NewPtr);
1331 return std::make_pair(
true,
false);
1334bool LegalizeBufferContentTypesVisitor::visitStoreInst(StoreInst &SI) {
1337 IRB.SetInsertPoint(&SI);
1338 SmallVector<uint32_t> AggIdxs;
1339 Value *OrigData =
SI.getValueOperand();
1340 auto [
Changed, ModifiedInPlace] =
1341 visitStoreImpl(SI, OrigData->
getType(), AggIdxs, 0, OrigData->
getName());
1342 if (
Changed && !ModifiedInPlace)
1343 SI.eraseFromParent();
1347bool LegalizeBufferContentTypesVisitor::visitAddrSpaceCastInst(
1348 AddrSpaceCastInst &AI) {
1353 auto Record = ZeroBasePointerToNumRecords.
find(Src);
1354 if (Record != ZeroBasePointerToNumRecords.
end())
1355 ZeroBasePointerToNumRecords.
insert({&AI,
Record->second});
1357 ZeroBasePointerToNumRecords.
insert({&AI,
nullptr});
1361bool LegalizeBufferContentTypesVisitor::visitIntrinsicInst(IntrinsicInst &
II) {
1362 if (
II.getIntrinsicID() != Intrinsic::amdgcn_make_buffer_rsrc)
1364 ZeroBasePointerToNumRecords.
insert({&
II,
II.getOperand(2)});
1368bool LegalizeBufferContentTypesVisitor::processFunction(
Function &
F,
1369 ScalarEvolution *SE) {
1376 ZeroBasePointerToNumRecords.
clear();
1383static std::pair<Constant *, Constant *>
1386 return std::make_pair(
C->getAggregateElement(0u),
C->getAggregateElement(1u));
1391class FatPtrConstMaterializer final :
public ValueMaterializer {
1392 BufferFatPtrToStructTypeMap *TypeMap;
1398 ValueMapper InternalMapper;
1400 Constant *materializeBufferFatPtrConst(Constant *
C);
1404 FatPtrConstMaterializer(BufferFatPtrToStructTypeMap *TypeMap,
1407 InternalMapper(UnderlyingMap,
RF_None, TypeMap, this) {}
1408 ~FatPtrConstMaterializer() =
default;
1414Constant *FatPtrConstMaterializer::materializeBufferFatPtrConst(Constant *
C) {
1415 Type *SrcTy =
C->getType();
1417 if (
C->isNullValue())
1418 return ConstantAggregateZero::getNullValue(NewTy);
1431 if (Constant *S =
VC->getSplatValue()) {
1436 auto EC =
VC->getType()->getElementCount();
1442 for (
Value *
Op :
VC->operand_values()) {
1457 "fat pointer) values are not supported");
1461 "constant exprs containing ptr addrspace(7) (buffer "
1462 "fat pointer) values should have been expanded earlier");
1467Value *FatPtrConstMaterializer::materialize(
Value *
V) {
1475 return materializeBufferFatPtrConst(
C);
1483class SplitPtrStructs :
public InstVisitor<SplitPtrStructs, PtrParts> {
1526 void processConditionals();
1575void SplitPtrStructs::copyMetadata(
Value *Dest,
Value *Src) {
1579 if (!DestI || !SrcI)
1582 DestI->copyMetadata(*SrcI);
1587 "of something that wasn't rewritten");
1588 auto *RsrcEntry = &RsrcParts[
V];
1589 auto *OffEntry = &OffParts[
V];
1590 if (*RsrcEntry && *OffEntry)
1591 return {*RsrcEntry, *OffEntry};
1595 return {*RsrcEntry = Rsrc, *OffEntry =
Off};
1598 IRBuilder<InstSimplifyFolder>::InsertPointGuard Guard(IRB);
1603 return {*RsrcEntry = Rsrc, *OffEntry =
Off};
1606 IRB.SetInsertPoint(*
I->getInsertionPointAfterDef());
1607 IRB.SetCurrentDebugLocation(
I->getDebugLoc());
1609 IRB.SetInsertPointPastAllocas(
A->getParent());
1610 IRB.SetCurrentDebugLocation(
DebugLoc());
1612 Value *Rsrc = IRB.CreateExtractValue(
V, 0,
V->getName() +
".rsrc");
1613 Value *
Off = IRB.CreateExtractValue(
V, 1,
V->getName() +
".off");
1614 return {*RsrcEntry = Rsrc, *OffEntry =
Off};
1627 V =
GEP->getPointerOperand();
1629 V = ASC->getPointerOperand();
1633void SplitPtrStructs::getPossibleRsrcRoots(Instruction *
I,
1634 SmallPtrSetImpl<Value *> &Roots,
1635 SmallPtrSetImpl<Value *> &Seen) {
1639 for (
Value *In :
PHI->incoming_values()) {
1646 if (!Seen.
insert(SI).second)
1661void SplitPtrStructs::processConditionals() {
1662 SmallDenseMap<Value *, Value *> FoundRsrcs;
1663 SmallPtrSet<Value *, 4> Roots;
1664 SmallPtrSet<Value *, 4> Seen;
1665 for (Instruction *
I : Conditionals) {
1667 Value *Rsrc = RsrcParts[
I];
1669 assert(Rsrc &&
Off &&
"must have visited conditionals by now");
1671 std::optional<Value *> MaybeRsrc;
1672 auto MaybeFoundRsrc = FoundRsrcs.
find(
I);
1673 if (MaybeFoundRsrc != FoundRsrcs.
end()) {
1674 MaybeRsrc = MaybeFoundRsrc->second;
1676 IRBuilder<InstSimplifyFolder>::InsertPointGuard Guard(IRB);
1679 getPossibleRsrcRoots(
I, Roots, Seen);
1696 if (Diff.size() == 1) {
1697 Value *RootVal = *Diff.begin();
1701 MaybeRsrc = getPtrParts(RootVal).first;
1703 MaybeRsrc = RootVal;
1711 IRB.SetInsertPoint(*
PHI->getInsertionPointAfterDef());
1712 IRB.SetCurrentDebugLocation(
PHI->getDebugLoc());
1714 NewRsrc = *MaybeRsrc;
1717 auto *RsrcPHI = IRB.CreatePHI(RsrcTy,
PHI->getNumIncomingValues());
1718 RsrcPHI->takeName(Rsrc);
1720 Value *VRsrc = getPtrParts(
V).first;
1721 RsrcPHI->addIncoming(VRsrc, BB);
1723 copyMetadata(RsrcPHI,
PHI);
1728 auto *NewOff = IRB.CreatePHI(OffTy,
PHI->getNumIncomingValues());
1729 NewOff->takeName(
Off);
1731 assert(OffParts.
count(
V) &&
"An offset part had to be created by now");
1732 Value *VOff = getPtrParts(
V).second;
1733 NewOff->addIncoming(VOff, BB);
1735 copyMetadata(NewOff,
PHI);
1745 RsrcInst->replaceAllUsesWith(NewRsrc);
1749 OffInst->replaceAllUsesWith(NewOff);
1755 FoundRsrcs[
V] = NewRsrc;
1760 if (RsrcInst != *MaybeRsrc) {
1762 RsrcInst->replaceAllUsesWith(*MaybeRsrc);
1766 FoundRsrcs[
V] = *MaybeRsrc;
1774void SplitPtrStructs::killAndReplaceSplitInstructions(
1775 SmallVectorImpl<Instruction *> &Origs) {
1776 for (Instruction *
I : ConditionalTemps)
1777 I->eraseFromParent();
1779 for (Instruction *
I : Origs) {
1785 for (DbgVariableRecord *Dbg : Dbgs) {
1786 auto &
DL =
I->getDataLayout();
1788 "We should've RAUW'd away loads, stores, etc. at this point");
1789 DbgVariableRecord *OffDbg =
Dbg->clone();
1790 auto [Rsrc,
Off] = getPtrParts(
I);
1792 int64_t RsrcSz =
DL.getTypeSizeInBits(Rsrc->
getType());
1793 int64_t OffSz =
DL.getTypeSizeInBits(
Off->getType());
1795 std::optional<DIExpression *> RsrcExpr =
1798 std::optional<DIExpression *> OffExpr =
1809 Dbg->setExpression(*RsrcExpr);
1810 Dbg->replaceVariableLocationOp(
I, Rsrc);
1817 I->replaceUsesWithIf(Poison, [&](
const Use &U) ->
bool {
1823 if (
I->use_empty()) {
1824 I->eraseFromParent();
1827 IRB.SetInsertPoint(*
I->getInsertionPointAfterDef());
1828 IRB.SetCurrentDebugLocation(
I->getDebugLoc());
1829 auto [Rsrc,
Off] = getPtrParts(
I);
1831 Struct = IRB.CreateInsertValue(Struct, Rsrc, 0);
1832 Struct = IRB.CreateInsertValue(Struct,
Off, 1);
1833 copyMetadata(Struct,
I);
1835 I->replaceAllUsesWith(Struct);
1836 I->eraseFromParent();
1840void SplitPtrStructs::setAlign(CallInst *Intr, Align
A,
unsigned RsrcArgIdx) {
1842 Intr->
addParamAttr(RsrcArgIdx, Attribute::getWithAlignment(Ctx,
A));
1848 case AtomicOrdering::Release:
1849 case AtomicOrdering::AcquireRelease:
1850 case AtomicOrdering::SequentiallyConsistent:
1851 IRB.CreateFence(AtomicOrdering::Release, SSID);
1861 case AtomicOrdering::Acquire:
1862 case AtomicOrdering::AcquireRelease:
1863 case AtomicOrdering::SequentiallyConsistent:
1864 IRB.CreateFence(AtomicOrdering::Acquire, SSID);
1871Value *SplitPtrStructs::handleMemoryInst(Instruction *
I,
Value *Arg,
Value *Ptr,
1872 Type *Ty, Align Alignment,
1875 IRB.SetInsertPoint(
I);
1877 auto [Rsrc,
Off] = getPtrParts(Ptr);
1880 Args.push_back(Arg);
1881 Args.push_back(Rsrc);
1883 insertPreMemOpFence(Order, SSID);
1887 Args.push_back(IRB.getInt32(0));
1892 Args.push_back(IRB.getInt32(Aux));
1896 IID = Order == AtomicOrdering::NotAtomic
1897 ? Intrinsic::amdgcn_raw_ptr_buffer_load
1898 : Intrinsic::amdgcn_raw_ptr_atomic_buffer_load;
1900 IID = Intrinsic::amdgcn_raw_ptr_buffer_store;
1902 switch (RMW->getOperation()) {
1904 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_swap;
1907 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_add;
1910 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_sub;
1913 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_and;
1916 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_or;
1919 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_xor;
1922 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_smax;
1925 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_smin;
1928 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_umax;
1931 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_umin;
1934 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_fadd;
1937 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_fmax;
1940 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_fmin;
1943 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_cond_sub_u32;
1946 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_sub_clamp_u32;
1950 "atomic floating point subtraction not supported for "
1951 "buffer resources and should've been expanded away");
1956 "atomic floating point fmaximum not supported for "
1957 "buffer resources and should've been expanded away");
1962 "atomic floating point fminimum not supported for "
1963 "buffer resources and should've been expanded away");
1968 "atomic floating point fmaximumnum not supported for "
1969 "buffer resources and should've been expanded away");
1974 "atomic floating point fminimumnum not supported for "
1975 "buffer resources and should've been expanded away");
1980 "atomic nand not supported for buffer resources and "
1981 "should've been expanded away");
1986 "wrapping increment/decrement not supported for "
1987 "buffer resources and should've been expanded away");
1994 CallInst *
Call = IRB.CreateIntrinsicWithoutFolding(IID, Ty, Args);
1995 copyMetadata(
Call,
I);
1996 setAlign(
Call, Alignment, Arg ? 1 : 0);
1999 insertPostMemOpFence(Order, SSID);
2003 I->replaceAllUsesWith(
Call);
2007PtrParts SplitPtrStructs::visitInstruction(Instruction &
I) {
2008 return {
nullptr,
nullptr};
2011PtrParts SplitPtrStructs::visitLoadInst(LoadInst &LI) {
2013 return {
nullptr,
nullptr};
2017 return {
nullptr,
nullptr};
2020PtrParts SplitPtrStructs::visitStoreInst(StoreInst &SI) {
2022 return {
nullptr,
nullptr};
2023 Value *Arg =
SI.getValueOperand();
2024 handleMemoryInst(&SI, Arg,
SI.getPointerOperand(), Arg->
getType(),
2025 SI.getAlign(),
SI.getOrdering(),
SI.isVolatile(),
2026 SI.getSyncScopeID());
2027 return {
nullptr,
nullptr};
2030PtrParts SplitPtrStructs::visitAtomicRMWInst(AtomicRMWInst &AI) {
2032 return {
nullptr,
nullptr};
2037 return {
nullptr,
nullptr};
2042PtrParts SplitPtrStructs::visitAtomicCmpXchgInst(AtomicCmpXchgInst &AI) {
2045 return {
nullptr,
nullptr};
2046 IRB.SetInsertPoint(&AI);
2051 bool IsNonTemporal = AI.
getMetadata(LLVMContext::MD_nontemporal);
2053 auto [Rsrc,
Off] = getPtrParts(Ptr);
2054 insertPreMemOpFence(Order, SSID);
2061 CallInst *
Call = IRB.CreateIntrinsicWithoutFolding(
2062 Intrinsic::amdgcn_raw_ptr_buffer_atomic_cmpswap, Ty,
2064 IRB.getInt32(0), IRB.getInt32(Aux)});
2065 copyMetadata(
Call, &AI);
2068 insertPostMemOpFence(Order, SSID);
2071 Res = IRB.CreateInsertValue(Res,
Call, 0);
2073 Res = IRB.CreateInsertValue(Res, Succeeded, 1);
2076 return {
nullptr,
nullptr};
2079PtrParts SplitPtrStructs::visitGetElementPtrInst(GetElementPtrInst &
GEP) {
2080 using namespace llvm::PatternMatch;
2081 Value *Ptr =
GEP.getPointerOperand();
2083 return {
nullptr,
nullptr};
2084 IRB.SetInsertPoint(&
GEP);
2086 auto [Rsrc,
Off] = getPtrParts(Ptr);
2087 const DataLayout &
DL =
GEP.getDataLayout();
2088 bool IsNUW =
GEP.hasNoUnsignedWrap();
2089 bool IsNUSW =
GEP.hasNoUnsignedSignedWrap();
2100 GEP.mutateType(FatPtrTy);
2102 GEP.mutateType(ResTy);
2104 if (BroadcastsPtr) {
2105 Rsrc = IRB.CreateVectorSplat(ResRsrcVecTy->getElementCount(), Rsrc,
2107 Off = IRB.CreateVectorSplat(ResRsrcVecTy->getElementCount(),
Off,
2115 bool HasNonNegativeOff =
false;
2117 HasNonNegativeOff = !CI->isNegative();
2123 NewOff = IRB.CreateAdd(
Off, OffAccum,
"",
2124 IsNUW || (IsNUSW && HasNonNegativeOff),
2127 copyMetadata(NewOff, &
GEP);
2130 return {Rsrc, NewOff};
2133PtrParts SplitPtrStructs::visitPtrToIntInst(PtrToIntInst &PI) {
2136 return {
nullptr,
nullptr};
2137 IRB.SetInsertPoint(&PI);
2142 auto [Rsrc,
Off] = getPtrParts(Ptr);
2148 Res = IRB.CreateIntCast(
Off, ResTy,
false,
2151 Value *RsrcInt = IRB.CreatePtrToInt(Rsrc, ResTy, PI.
getName() +
".rsrc");
2152 Value *Shl = IRB.CreateShl(
2155 "", Width >= FatPtrWidth, Width > FatPtrWidth);
2156 Value *OffCast = IRB.CreateIntCast(
Off, ResTy,
false,
2158 Res = IRB.CreateOr(Shl, OffCast);
2161 copyMetadata(Res, &PI);
2165 return {
nullptr,
nullptr};
2168PtrParts SplitPtrStructs::visitPtrToAddrInst(PtrToAddrInst &PA) {
2171 return {
nullptr,
nullptr};
2172 IRB.SetInsertPoint(&PA);
2174 auto [Rsrc,
Off] = getPtrParts(Ptr);
2176 copyMetadata(Res, &PA);
2180 return {
nullptr,
nullptr};
2183PtrParts SplitPtrStructs::visitIntToPtrInst(IntToPtrInst &IP) {
2185 return {
nullptr,
nullptr};
2186 IRB.SetInsertPoint(&IP);
2195 Type *RsrcTy = RetTy->getElementType(0);
2196 Type *OffTy = RetTy->getElementType(1);
2205 RsrcInt = IRB.CreateIntCast(RsrcPart, RsrcIntTy,
false);
2207 Value *Rsrc = IRB.CreateIntToPtr(RsrcInt, RsrcTy, IP.
getName() +
".rsrc");
2209 IRB.CreateIntCast(
Int, OffTy,
false, IP.
getName() +
".off");
2211 copyMetadata(Rsrc, &IP);
2216PtrParts SplitPtrStructs::visitAddrSpaceCastInst(AddrSpaceCastInst &
I) {
2220 return {
nullptr,
nullptr};
2221 IRB.SetInsertPoint(&
I);
2224 if (
In->getType() ==
I.getType()) {
2225 auto [Rsrc,
Off] = getPtrParts(In);
2231 Type *RsrcTy = ResTy->getElementType(0);
2232 Type *OffTy = ResTy->getElementType(1);
2238 if (InConst && InConst->isNullValue()) {
2241 return {NullRsrc, ZeroOff};
2247 return {PoisonRsrc, PoisonOff};
2253 return {UndefRsrc, UndefOff};
2258 "only buffer resources (addrspace 8) and null/poison pointers can be "
2259 "cast to buffer fat pointers (addrspace 7)");
2261 return {
In, ZeroOff};
2264PtrParts SplitPtrStructs::visitICmpInst(ICmpInst &Cmp) {
2267 return {
nullptr,
nullptr};
2269 IRB.SetInsertPoint(&Cmp);
2270 ICmpInst::Predicate
Pred =
Cmp.getPredicate();
2272 assert((
Pred == ICmpInst::ICMP_EQ ||
Pred == ICmpInst::ICMP_NE) &&
2273 "Pointer comparison is only equal or unequal");
2274 auto [LhsRsrc, LhsOff] = getPtrParts(Lhs);
2275 auto [RhsRsrc, RhsOff] = getPtrParts(Rhs);
2276 Value *Res = IRB.CreateICmp(
Pred, LhsOff, RhsOff);
2277 copyMetadata(Res, &Cmp);
2280 Cmp.replaceAllUsesWith(Res);
2281 return {
nullptr,
nullptr};
2284PtrParts SplitPtrStructs::visitFreezeInst(FreezeInst &
I) {
2286 return {
nullptr,
nullptr};
2287 IRB.SetInsertPoint(&
I);
2288 auto [Rsrc,
Off] = getPtrParts(
I.getOperand(0));
2290 Value *RsrcRes = IRB.CreateFreeze(Rsrc,
I.getName() +
".rsrc");
2291 copyMetadata(RsrcRes, &
I);
2292 Value *OffRes = IRB.CreateFreeze(
Off,
I.getName() +
".off");
2293 copyMetadata(OffRes, &
I);
2295 return {RsrcRes, OffRes};
2298PtrParts SplitPtrStructs::visitExtractElementInst(ExtractElementInst &
I) {
2300 return {
nullptr,
nullptr};
2301 IRB.SetInsertPoint(&
I);
2302 Value *Vec =
I.getVectorOperand();
2304 auto [Rsrc,
Off] = getPtrParts(Vec);
2306 Value *RsrcRes = IRB.CreateExtractElement(Rsrc, Idx,
I.getName() +
".rsrc");
2307 copyMetadata(RsrcRes, &
I);
2308 Value *OffRes = IRB.CreateExtractElement(
Off, Idx,
I.getName() +
".off");
2309 copyMetadata(OffRes, &
I);
2311 return {RsrcRes, OffRes};
2314PtrParts SplitPtrStructs::visitInsertElementInst(InsertElementInst &
I) {
2318 return {
nullptr,
nullptr};
2319 IRB.SetInsertPoint(&
I);
2320 Value *Vec =
I.getOperand(0);
2321 Value *Elem =
I.getOperand(1);
2323 auto [VecRsrc, VecOff] = getPtrParts(Vec);
2324 auto [ElemRsrc, ElemOff] = getPtrParts(Elem);
2327 IRB.CreateInsertElement(VecRsrc, ElemRsrc, Idx,
I.getName() +
".rsrc");
2328 copyMetadata(RsrcRes, &
I);
2330 IRB.CreateInsertElement(VecOff, ElemOff, Idx,
I.getName() +
".off");
2331 copyMetadata(OffRes, &
I);
2333 return {RsrcRes, OffRes};
2336PtrParts SplitPtrStructs::visitShuffleVectorInst(ShuffleVectorInst &
I) {
2339 return {
nullptr,
nullptr};
2340 IRB.SetInsertPoint(&
I);
2343 Value *V2 =
I.getOperand(1);
2344 ArrayRef<int>
Mask =
I.getShuffleMask();
2345 auto [V1Rsrc, V1Off] = getPtrParts(
V1);
2346 auto [V2Rsrc, V2Off] = getPtrParts(V2);
2349 IRB.CreateShuffleVector(V1Rsrc, V2Rsrc, Mask,
I.getName() +
".rsrc");
2350 copyMetadata(RsrcRes, &
I);
2352 IRB.CreateShuffleVector(V1Off, V2Off, Mask,
I.getName() +
".off");
2353 copyMetadata(OffRes, &
I);
2355 return {RsrcRes, OffRes};
2358PtrParts SplitPtrStructs::visitPHINode(PHINode &
PHI) {
2360 return {
nullptr,
nullptr};
2361 IRB.SetInsertPoint(*
PHI.getInsertionPointAfterDef());
2367 Value *TmpRsrc = IRB.CreateExtractValue(&
PHI, 0,
PHI.getName() +
".rsrc");
2368 Value *TmpOff = IRB.CreateExtractValue(&
PHI, 1,
PHI.getName() +
".off");
2369 Conditionals.push_back(&
PHI);
2371 return {TmpRsrc, TmpOff};
2374PtrParts SplitPtrStructs::visitSelectInst(SelectInst &SI) {
2376 return {
nullptr,
nullptr};
2377 IRB.SetInsertPoint(&SI);
2382 auto [TrueRsrc, TrueOff] = getPtrParts(
True);
2383 auto [FalseRsrc, FalseOff] = getPtrParts(
False);
2386 IRB.CreateSelect(
Cond, TrueRsrc, FalseRsrc,
SI.getName() +
".rsrc", &SI);
2387 copyMetadata(RsrcRes, &SI);
2388 Conditionals.push_back(&SI);
2390 IRB.CreateSelect(
Cond, TrueOff, FalseOff,
SI.getName() +
".off", &SI);
2391 copyMetadata(OffRes, &SI);
2393 return {RsrcRes, OffRes};
2404 case Intrinsic::amdgcn_make_buffer_rsrc:
2405 case Intrinsic::ptrmask:
2406 case Intrinsic::invariant_start:
2407 case Intrinsic::invariant_end:
2408 case Intrinsic::launder_invariant_group:
2409 case Intrinsic::memcpy:
2410 case Intrinsic::memcpy_inline:
2411 case Intrinsic::memmove:
2412 case Intrinsic::memset:
2413 case Intrinsic::memset_inline:
2414 case Intrinsic::experimental_memset_pattern:
2415 case Intrinsic::amdgcn_load_to_lds:
2416 case Intrinsic::amdgcn_load_async_to_lds:
2421PtrParts SplitPtrStructs::visitIntrinsicInst(IntrinsicInst &
I) {
2426 case Intrinsic::amdgcn_make_buffer_rsrc: {
2428 return {
nullptr,
nullptr};
2430 Value *Stride =
I.getArgOperand(1);
2431 Value *NumRecords =
I.getArgOperand(2);
2434 Type *RsrcType = SplitType->getElementType(0);
2435 Type *OffType = SplitType->getElementType(1);
2436 IRB.SetInsertPoint(&
I);
2437 Value *Rsrc = IRB.CreateIntrinsic(
2438 IID, {RsrcType,
Base->getType(), NumRecords->
getType()},
2440 copyMetadata(Rsrc, &
I);
2444 return {Rsrc,
Zero};
2446 case Intrinsic::ptrmask: {
2447 Value *Ptr =
I.getArgOperand(0);
2449 return {
nullptr,
nullptr};
2451 IRB.SetInsertPoint(&
I);
2452 auto [Rsrc,
Off] = getPtrParts(Ptr);
2453 if (
Mask->getType() !=
Off->getType())
2455 "pointer (data layout not set up correctly?)");
2456 Value *OffRes = IRB.CreateAnd(
Off, Mask,
I.getName() +
".off");
2457 copyMetadata(OffRes, &
I);
2459 return {Rsrc, OffRes};
2463 case Intrinsic::invariant_start: {
2464 Value *Ptr =
I.getArgOperand(1);
2466 return {
nullptr,
nullptr};
2467 IRB.SetInsertPoint(&
I);
2468 auto [Rsrc,
Off] = getPtrParts(Ptr);
2470 auto *NewRsrc = IRB.CreateIntrinsic(IID, {NewTy}, {
I.getOperand(0), Rsrc});
2471 copyMetadata(NewRsrc, &
I);
2474 I.replaceAllUsesWith(NewRsrc);
2475 return {
nullptr,
nullptr};
2477 case Intrinsic::invariant_end: {
2478 Value *RealPtr =
I.getArgOperand(2);
2480 return {
nullptr,
nullptr};
2481 IRB.SetInsertPoint(&
I);
2482 Value *RealRsrc = getPtrParts(RealPtr).first;
2483 Value *InvPtr =
I.getArgOperand(0);
2485 Value *NewRsrc = IRB.CreateIntrinsic(IID, {RealRsrc->
getType()},
2486 {InvPtr,
Size, RealRsrc});
2487 copyMetadata(NewRsrc, &
I);
2490 I.replaceAllUsesWith(NewRsrc);
2491 return {
nullptr,
nullptr};
2493 case Intrinsic::launder_invariant_group: {
2494 Value *Ptr =
I.getArgOperand(0);
2496 return {
nullptr,
nullptr};
2497 IRB.SetInsertPoint(&
I);
2498 auto [Rsrc,
Off] = getPtrParts(Ptr);
2499 Value *NewRsrc = IRB.CreateIntrinsic(IID, {Rsrc->
getType()}, {Rsrc});
2500 copyMetadata(NewRsrc, &
I);
2503 return {NewRsrc,
Off};
2505 case Intrinsic::amdgcn_load_to_lds:
2506 case Intrinsic::amdgcn_load_async_to_lds: {
2507 Value *Ptr =
I.getArgOperand(0);
2509 return {
nullptr,
nullptr};
2510 IRB.SetInsertPoint(&
I);
2511 auto [Rsrc,
Off] = getPtrParts(Ptr);
2512 Value *LDSPtr =
I.getArgOperand(1);
2513 Value *LoadSize =
I.getArgOperand(2);
2514 Value *ImmOff =
I.getArgOperand(3);
2515 Value *Aux =
I.getArgOperand(4);
2516 Value *SOffset = IRB.getInt32(0);
2518 IID == Intrinsic::amdgcn_load_to_lds
2519 ? Intrinsic::amdgcn_raw_ptr_buffer_load_lds
2520 : Intrinsic::amdgcn_raw_ptr_buffer_load_async_lds;
2521 Instruction *NewLoad = IRB.CreateIntrinsicWithoutFolding(
2522 NewIntr, {}, {Rsrc, LDSPtr, LoadSize,
Off, SOffset, ImmOff, Aux});
2523 copyMetadata(NewLoad, &
I);
2525 I.replaceAllUsesWith(NewLoad);
2526 return {
nullptr,
nullptr};
2528 case Intrinsic::prefetch: {
2529 Value *Ptr =
I.getArgOperand(0);
2531 return {
nullptr,
nullptr};
2535 if (ST->hasSafeSmemPrefetch() &&
2537 IRB.SetInsertPoint(&
I);
2538 auto [Rsrc,
Off] = getPtrParts(Ptr);
2541 *ST, ConstOff->getZExtValue(),
true)) {
2542 Value *NewPrefetch =
2543 IRB.CreateIntrinsic(Intrinsic::amdgcn_s_buffer_prefetch_data, {},
2544 {Rsrc, ConstOff, IRB.getInt32(0)});
2545 copyMetadata(NewPrefetch, &
I);
2549 return {
nullptr,
nullptr};
2551 case Intrinsic::amdgcn_s_prefetch_data:
2552 case Intrinsic::amdgcn_s_prefetch_inst:
2554 return {
nullptr,
nullptr};
2557 return {
nullptr,
nullptr};
2559 return {
nullptr,
nullptr};
2562void SplitPtrStructs::processFunction(
Function &
F) {
2564 SmallVector<Instruction *, 0> Originals(
2566 LLVM_DEBUG(
dbgs() <<
"Splitting pointer structs in function: " <<
F.getName()
2568 for (Instruction *
I : Originals) {
2577 "Can't have a resource but no offset");
2579 RsrcParts[
I] = Rsrc;
2583 processConditionals();
2584 killAndReplaceSplitInstructions(Originals);
2590 Conditionals.clear();
2591 ConditionalTemps.clear();
2595class AMDGPULowerBufferFatPointers :
public ModulePass {
2599 AMDGPULowerBufferFatPointers() : ModulePass(
ID) {}
2602 bool runOnModule(
Module &M)
override;
2604 void getAnalysisUsage(AnalysisUsage &AU)
const override;
2612 BufferFatPtrToStructTypeMap *TypeMap) {
2613 bool HasFatPointers =
false;
2616 HasFatPointers |= (
I.getType() != TypeMap->remapType(
I.getType()));
2618 for (
const Value *
V :
I.operand_values())
2619 HasFatPointers |= (
V->getType() != TypeMap->remapType(
V->getType()));
2621 return HasFatPointers;
2625 BufferFatPtrToStructTypeMap *TypeMap) {
2626 Type *Ty =
F.getFunctionType();
2627 return Ty != TypeMap->remapType(Ty);
2643 while (!OldF->
empty()) {
2657 CloneMap[&NewArg] = &OldArg;
2658 NewArg.takeName(&OldArg);
2659 Type *OldArgTy = OldArg.getType(), *NewArgTy = NewArg.getType();
2661 NewArg.mutateType(OldArgTy);
2662 OldArg.replaceAllUsesWith(&NewArg);
2663 NewArg.mutateType(NewArgTy);
2667 if (OldArgTy != NewArgTy && !IsIntrinsic)
2670 AttributeFuncs::typeIncompatible(NewArgTy, ArgAttr));
2677 AttributeFuncs::typeIncompatible(NewF->
getReturnType(), RetAttrs));
2679 NewF->
getContext(), OldAttrs.getFnAttrs(), RetAttrs, ArgAttrs));
2687 CloneMap[&BB] = &BB;
2693bool AMDGPULowerBufferFatPointers::run(
Module &M,
const TargetMachine &TM,
2696 const DataLayout &
DL =
M.getDataLayout();
2702 LLVMContext &Ctx =
M.getContext();
2704 BufferFatPtrToStructTypeMap StructTM(
DL);
2705 BufferFatPtrToIntTypeMap IntTM(
DL);
2709 Ctx.
emitError(
"global variables with a buffer fat pointer address "
2710 "space (7) are not supported");
2712 GV.eraseFromParent();
2717 Type *VT = GV.getValueType();
2718 if (VT != StructTM.remapType(VT)) {
2720 Ctx.
emitError(
"global variables that contain buffer fat pointers "
2721 "(address space 7 pointers) are unsupported. Use "
2722 "buffer resource pointers (address space 8) instead");
2724 GV.eraseFromParent();
2740 SmallPtrSet<Constant *, 8> Visited;
2741 SetVector<Constant *> BufferFatPtrConsts;
2742 while (!Worklist.
empty()) {
2744 if (!Visited.
insert(
C).second)
2760 StoreFatPtrsAsIntsAndExpandMemcpyVisitor MemOpsRewrite(&IntTM, M);
2761 LegalizeBufferContentTypesVisitor BufferContentsTypeRewrite(M, &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(M, &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
#define INITIALIZE_PASS_DEPENDENCY(depName)
#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis)
#define INITIALIZE_PASS_BEGIN(passName, arg, name, cfg, analysis)
SmallVector< MachineOperand, 4 > 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 ...
uint64_t getMaxBufferIntrinsicWidth(const DataLayout &DL, Type *T, Align A, bool NoWrapFromMax, bool NoPartialOOB) const
Return the maximum allowed load/store width for the given type and alignment combination based on sub...
bool hasRelaxedBufferOOBMode() 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.
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 * getMinusSCEV(SCEVUse LHS, SCEVUse RHS, SCEVFlags Flags=SCEV::FlagNone, unsigned Depth=0)
Return LHS-RHS.
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 SCEVUse getAddExpr(SmallVectorImpl< SCEVUse > &Ops, SCEVFlagsPair Flags={}, unsigned Depth=0)
Get a canonical add expression, or something simpler if possible.
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 * 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.
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 ScalarTy getFixedValue() const
constexpr bool isFixed() const
Returns true if the quantity is not scaled by vscale.
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.
bool isLegalSMRDEncodedSignedOffset(const MCSubtargetInfo &ST, int64_t EncodedOffset, bool IsBuffer)
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< true > 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.
PointerTypeMap run(const Module &M)
Compute the PointerTypeMap for the 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.
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.
IRBuilder(LLVMContext &, FolderTy, InserterTy) -> IRBuilder< FolderTy, InserterTy >
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.
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.
constexpr auto seq(T Begin, T End)
Iterate over an integral type from Begin up to - but not including - End.
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.