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;
448 Type *Ty, SmallVectorImpl<unsigned> &AggIdxs,
uint64_t Off,
450 function_ref<
void(
Type *LeafTy,
Type *IntLeafTy, ArrayRef<unsigned> Idxs,
455 StoreFatPtrsAsIntsAndExpandMemcpyVisitor(BufferFatPtrToIntTypeMap *TypeMap,
456 const DataLayout &
DL,
458 : TypeMap(TypeMap), IRB(Ctx, InstSimplifyFolder(
DL)),
DL(
DL) {}
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.CreatePtrAdd(
479 Ptr, ConstantInt::get(
DL.getIndexType(Ptr->
getType()), Off),
483void StoreFatPtrsAsIntsAndExpandMemcpyVisitor::forEachAggLeaf(
484 Type *Ty, SmallVectorImpl<unsigned> &AggIdxs,
uint64_t Off,
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);
736 Value *arrayToVector(
Value *V,
Type *TargetType,
const Twine &Name);
737 Value *vectorToArray(
Value *V,
Type *OrigType,
const Twine &Name);
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) {}
780 uint64_t maxIntrinsicWidth(
Type *Ty, Align
A, OobProperties OobProps);
787 Value *makeLegalNonAggregate(
Value *V,
Type *TargetType,
const Twine &Name);
788 Value *makeIllegalNonAggregate(
Value *V,
Type *OrigType,
const Twine &Name);
802 SmallVectorImpl<VecSlice> &Slices);
804 Value *extractSlice(
Value *Vec, VecSlice S,
const Twine &Name);
805 Value *insertSlice(
Value *Whole,
Value *Part, VecSlice S,
const Twine &Name);
815 Type *intrinsicTypeFor(
Type *LegalType);
817 bool visitLoadImpl(LoadInst &OrigLI,
Type *PartType,
818 SmallVectorImpl<uint32_t> &AggIdxs,
uint64_t AggByteOffset,
819 Value *&Result,
const Twine &Name);
821 std::pair<bool, bool> visitStoreImpl(StoreInst &OrigSI,
Type *PartType,
822 SmallVectorImpl<uint32_t> &AggIdxs,
826 bool visitInstruction(Instruction &
I) {
return false; }
827 bool visitLoadInst(LoadInst &LI);
828 bool visitStoreInst(StoreInst &SI);
831 bool visitIntrinsicInst(IntrinsicInst &
II);
832 bool visitAddrSpaceCastInst(AddrSpaceCastInst &ASCI);
835 LegalizeBufferContentTypesVisitor(
const DataLayout &
DL, LLVMContext &Ctx,
836 const TargetMachine *TM)
837 : IRB(Ctx, InstSimplifyFolder(
DL)),
DL(
DL), TM(TM) {}
842Type *LegalizeBufferContentTypesVisitor::scalarArrayTypeAsVector(
Type *
T) {
846 Type *ET = AT->getElementType();
849 "should have recursed");
850 if (!
DL.typeSizeEqualsStoreSize(AT))
852 "loading padded arrays from buffer fat pinters should have recursed");
856Value *LegalizeBufferContentTypesVisitor::arrayToVector(
Value *V,
861 unsigned EC = VT->getNumElements();
862 for (
auto I : iota_range<unsigned>(0, EC,
false)) {
863 Value *Elem = IRB.CreateExtractValue(V,
I, Name +
".elem." + Twine(
I));
864 VectorRes = IRB.CreateInsertElement(VectorRes, Elem,
I,
865 Name +
".as.vec." + Twine(
I));
870Value *LegalizeBufferContentTypesVisitor::vectorToArray(
Value *V,
875 unsigned EC = AT->getNumElements();
876 for (
auto I : iota_range<unsigned>(0, EC,
false)) {
877 Value *Elem = IRB.CreateExtractElement(V,
I, Name +
".elem." + Twine(
I));
878 ArrayRes = IRB.CreateInsertValue(ArrayRes, Elem,
I,
879 Name +
".as.array." + Twine(
I));
884LegalizeBufferContentTypesVisitor::OobProperties
885LegalizeBufferContentTypesVisitor::analyzeOobProperties(
Value *Ptr,
Type *Ty,
887 OobProperties
Result(
false,
false);
890 return OobProperties(
true,
true);
896 const SCEV *PtrOp = SE->
getSCEV(Ptr);
902 Value *PtrBaseVal = PtrBase->getValue();
909 auto NumRecordsIfKnown = ZeroBasePointerToNumRecords.
find(PtrBaseVal);
910 if (NumRecordsIfKnown == ZeroBasePointerToNumRecords.
end())
913 unsigned TypeSize =
DL.getTypeStoreSize(Ty).getKnownMinValue();
918 Result.NoWrapFromMax =
true;
922 if (!NumRecordsIfKnown->second)
924 const SCEV *NumRecords = SE->
getSCEV(NumRecordsIfKnown->second);
927 std::optional<unsigned> MaybeNumRecordsWidth =
929 if (!MaybeNumRecordsWidth)
931 unsigned NumRecordsWidth = *MaybeNumRecordsWidth;
932 Type *NumRecordsTy = IRB.getIntNTy(NumRecordsWidth);
934 Type *CompareTy = IRB.getInt64Ty();
942 Result.NoPartialOOB =
true;
944 const SCEV *BoundsDiff =
949 Result.NoPartialOOB =
true;
954LegalizeBufferContentTypesVisitor::maxIntrinsicWidth(
Type *
T, Align
A,
955 OobProperties OobProps) {
961 TypeSize ElemBits =
DL.getTypeSizeInBits(VT->getElementType());
968 if (!OobProps.NoWrapFromMax)
987 if (!OobProps.NoPartialOOB)
992 return Result.value() * 8;
995Type *LegalizeBufferContentTypesVisitor::legalNonAggregateForMemOp(
997 TypeSize
Size =
DL.getTypeStoreSizeInBits(
T);
999 if (!
DL.typeSizeEqualsStoreSize(
T))
1000 T = IRB.getIntNTy(
Size.getFixedValue());
1007 unsigned ElemSize =
DL.getTypeSizeInBits(ElemTy).getFixedValue();
1008 if (
isPowerOf2_32(ElemSize) && ElemSize >= 16 && ElemSize <= MaxWidth) {
1014 Type *BestVectorElemType =
nullptr;
1015 if (
Size.isKnownMultipleOf(32) && MaxWidth >= 32)
1016 BestVectorElemType = IRB.getInt32Ty();
1017 else if (
Size.isKnownMultipleOf(16) && MaxWidth >= 16)
1018 BestVectorElemType = IRB.getInt16Ty();
1020 BestVectorElemType = IRB.getInt8Ty();
1021 unsigned NumCastElems =
1023 if (NumCastElems == 1)
1024 return BestVectorElemType;
1028Value *LegalizeBufferContentTypesVisitor::makeLegalNonAggregate(
1029 Value *V,
Type *TargetType,
const Twine &Name) {
1030 Type *SourceType =
V->getType();
1031 TypeSize SourceSize =
DL.getTypeSizeInBits(SourceType);
1032 TypeSize TargetSize =
DL.getTypeSizeInBits(TargetType);
1033 if (SourceSize != TargetSize) {
1036 Value *AsScalar = IRB.CreateBitCast(V, ShortScalarTy, Name +
".as.scalar");
1037 Value *Zext = IRB.CreateZExt(AsScalar, ByteScalarTy, Name +
".zext");
1039 SourceType = ByteScalarTy;
1041 return IRB.CreateBitCast(V, TargetType, Name +
".legal");
1044Value *LegalizeBufferContentTypesVisitor::makeIllegalNonAggregate(
1045 Value *V,
Type *OrigType,
const Twine &Name) {
1046 Type *LegalType =
V->getType();
1047 TypeSize LegalSize =
DL.getTypeSizeInBits(LegalType);
1048 TypeSize OrigSize =
DL.getTypeSizeInBits(OrigType);
1049 if (LegalSize != OrigSize) {
1052 Value *AsScalar = IRB.CreateBitCast(V, ByteScalarTy, Name +
".bytes.cast");
1053 Value *Trunc = IRB.CreateTrunc(AsScalar, ShortScalarTy, Name +
".trunc");
1054 return IRB.CreateBitCast(Trunc, OrigType, Name +
".orig");
1056 return IRB.CreateBitCast(V, OrigType, Name +
".real.ty");
1059Type *LegalizeBufferContentTypesVisitor::intrinsicTypeFor(
Type *LegalType) {
1063 Type *ET = VT->getElementType();
1066 if (VT->getNumElements() == 1)
1068 if (
DL.getTypeSizeInBits(LegalType) == 96 &&
DL.getTypeSizeInBits(ET) < 32)
1071 switch (VT->getNumElements()) {
1075 return IRB.getInt8Ty();
1077 return IRB.getInt16Ty();
1079 return IRB.getInt32Ty();
1089void LegalizeBufferContentTypesVisitor::getVecSlices(
1090 Type *
T,
uint64_t MaxWidth, SmallVectorImpl<VecSlice> &Slices) {
1097 DL.getTypeSizeInBits(VT->getElementType()).getFixedValue();
1099 uint64_t ElemsPer4Words = 128 / ElemBitWidth;
1100 uint64_t ElemsPer2Words = ElemsPer4Words / 2;
1101 uint64_t ElemsPerWord = ElemsPer2Words / 2;
1102 uint64_t ElemsPerShort = ElemsPerWord / 2;
1103 uint64_t ElemsPerByte = ElemsPerShort / 2;
1107 uint64_t ElemsPer3Words = ElemsPerWord * 3;
1109 uint64_t TotalElems = VT->getNumElements();
1111 auto TrySlice = [&](
unsigned MaybeLen,
unsigned Width) {
1112 if (MaybeLen > 0 && Width <= MaxWidth && Index + MaybeLen <= TotalElems) {
1113 VecSlice Slice{
Index, MaybeLen};
1120 while (Index < TotalElems) {
1121 TrySlice(ElemsPer4Words, 128) || TrySlice(ElemsPer3Words, 96) ||
1122 TrySlice(ElemsPer2Words, 64) || TrySlice(ElemsPerWord, 32) ||
1123 TrySlice(ElemsPerShort, 16) || TrySlice(ElemsPerByte, 8);
1127Value *LegalizeBufferContentTypesVisitor::extractSlice(
Value *Vec, VecSlice S,
1128 const Twine &Name) {
1132 if (S.Length == VecVT->getNumElements() && S.Index == 0)
1135 return IRB.CreateExtractElement(Vec, S.Index,
1136 Name +
".slice." + Twine(S.Index));
1138 llvm::iota_range<int>(S.Index, S.Index + S.Length,
false));
1139 return IRB.CreateShuffleVector(Vec, Mask, Name +
".slice." + Twine(S.Index));
1142Value *LegalizeBufferContentTypesVisitor::insertSlice(
Value *Whole,
Value *Part,
1144 const Twine &Name) {
1148 if (S.Length == WholeVT->getNumElements() && S.Index == 0)
1150 if (S.Length == 1) {
1151 return IRB.CreateInsertElement(Whole, Part, S.Index,
1152 Name +
".slice." + Twine(S.Index));
1157 SmallVector<int> ExtPartMask(NumElems, -1);
1162 Value *ExtPart = IRB.CreateShuffleVector(Part, ExtPartMask,
1163 Name +
".ext." + Twine(S.Index));
1165 SmallVector<int>
Mask =
1170 return IRB.CreateShuffleVector(Whole, ExtPart, Mask,
1171 Name +
".parts." + Twine(S.Index));
1174bool LegalizeBufferContentTypesVisitor::visitLoadImpl(
1175 LoadInst &OrigLI,
Type *PartType, SmallVectorImpl<uint32_t> &AggIdxs,
1178 const StructLayout *Layout =
DL.getStructLayout(ST);
1180 for (
auto [
I, ElemTy,
Offset] :
1183 Changed |= visitLoadImpl(OrigLI, ElemTy, AggIdxs,
1184 AggByteOff +
Offset.getFixedValue(), Result,
1185 Name +
"." + Twine(
I));
1191 Type *ElemTy = AT->getElementType();
1194 TypeSize ElemAllocSize =
DL.getTypeAllocSize(ElemTy);
1196 for (
auto I : llvm::iota_range<uint32_t>(0, AT->getNumElements(),
1199 Changed |= visitLoadImpl(OrigLI, ElemTy, AggIdxs,
1201 Result, Name + Twine(
I));
1211 Type *ArrayAsVecType = scalarArrayTypeAsVector(PartType);
1212 OobProperties OobProps =
1214 uint64_t MaxWidth = maxIntrinsicWidth(ArrayAsVecType, PartAlign, OobProps);
1215 Type *LegalType = legalNonAggregateForMemOp(ArrayAsVecType, MaxWidth);
1218 getVecSlices(LegalType, MaxWidth, Slices);
1219 bool HasSlices = Slices.
size() > 1;
1220 bool IsAggPart = !AggIdxs.
empty();
1222 if (!HasSlices && !IsAggPart) {
1223 Type *LoadableType = intrinsicTypeFor(LegalType);
1224 if (LoadableType == PartType)
1227 IRB.SetInsertPoint(&OrigLI);
1229 NLI->mutateType(LoadableType);
1230 NLI = IRB.Insert(NLI);
1231 NLI->setName(Name +
".loadable");
1233 LoadsRes = IRB.CreateBitCast(NLI, LegalType, Name +
".from.loadable");
1235 IRB.SetInsertPoint(&OrigLI);
1243 unsigned ElemBytes =
DL.getTypeStoreSize(ElemType);
1245 if (IsAggPart && Slices.
empty())
1247 for (VecSlice S : Slices) {
1250 int64_t ByteOffset = AggByteOff + S.Index * ElemBytes;
1252 Value *NewPtr = IRB.CreateGEP(
1254 OrigPtr->
getName() +
".off.ptr." + Twine(ByteOffset),
1257 Type *LoadableType = intrinsicTypeFor(SliceType);
1258 LoadInst *NewLI = IRB.CreateAlignedLoad(
1260 Name +
".off." + Twine(ByteOffset));
1266 Value *
Loaded = IRB.CreateBitCast(NewLI, SliceType,
1267 NewLI->
getName() +
".from.loadable");
1268 LoadsRes = insertSlice(LoadsRes, Loaded, S, Name);
1271 if (LegalType != ArrayAsVecType)
1272 LoadsRes = makeIllegalNonAggregate(LoadsRes, ArrayAsVecType, Name);
1273 if (ArrayAsVecType != PartType)
1274 LoadsRes = vectorToArray(LoadsRes, PartType, Name);
1277 Result = IRB.CreateInsertValue(Result, LoadsRes, AggIdxs, Name);
1283bool LegalizeBufferContentTypesVisitor::visitLoadInst(LoadInst &LI) {
1287 SmallVector<uint32_t> AggIdxs;
1290 bool Changed = visitLoadImpl(LI, OrigType, AggIdxs, 0, Result, LI.
getName());
1299std::pair<bool, bool> LegalizeBufferContentTypesVisitor::visitStoreImpl(
1300 StoreInst &OrigSI,
Type *PartType, SmallVectorImpl<uint32_t> &AggIdxs,
1301 uint64_t AggByteOff,
const Twine &Name) {
1303 const StructLayout *Layout =
DL.getStructLayout(ST);
1305 for (
auto [
I, ElemTy,
Offset] :
1308 Changed |= std::get<0>(visitStoreImpl(OrigSI, ElemTy, AggIdxs,
1309 AggByteOff +
Offset.getFixedValue(),
1310 Name +
"." + Twine(
I)));
1313 return std::make_pair(
Changed,
false);
1316 Type *ElemTy = AT->getElementType();
1319 TypeSize ElemAllocSize =
DL.getTypeAllocSize(ElemTy);
1321 for (
auto I : llvm::iota_range<uint32_t>(0, AT->getNumElements(),
1324 Changed |= std::get<0>(visitStoreImpl(
1325 OrigSI, ElemTy, AggIdxs,
1329 return std::make_pair(
Changed,
false);
1334 Value *NewData = OrigData;
1336 bool IsAggPart = !AggIdxs.
empty();
1338 NewData = IRB.CreateExtractValue(NewData, AggIdxs, Name);
1340 Type *ArrayAsVecType = scalarArrayTypeAsVector(PartType);
1341 if (ArrayAsVecType != PartType) {
1342 NewData = arrayToVector(NewData, ArrayAsVecType, Name);
1346 OobProperties OobProps =
1348 uint64_t MaxWidth = maxIntrinsicWidth(ArrayAsVecType, PartAlign, OobProps);
1349 Type *LegalType = legalNonAggregateForMemOp(ArrayAsVecType, MaxWidth);
1350 if (LegalType != ArrayAsVecType) {
1351 NewData = makeLegalNonAggregate(NewData, LegalType, Name);
1355 getVecSlices(LegalType, MaxWidth, Slices);
1356 bool NeedToSplit = Slices.
size() > 1 || IsAggPart;
1358 Type *StorableType = intrinsicTypeFor(LegalType);
1359 if (StorableType == PartType)
1360 return std::make_pair(
false,
false);
1361 NewData = IRB.CreateBitCast(NewData, StorableType, Name +
".storable");
1363 return std::make_pair(
true,
true);
1368 if (IsAggPart && Slices.
empty())
1370 unsigned ElemBytes =
DL.getTypeStoreSize(ElemType);
1372 for (VecSlice S : Slices) {
1375 int64_t ByteOffset = AggByteOff + S.Index * ElemBytes;
1376 Value *NewPtr = IRB.CreateGEP(
1377 IRB.getInt8Ty(), OrigPtr, IRB.getInt32(ByteOffset),
1378 OrigPtr->
getName() +
".part." + Twine(S.Index),
1381 Value *DataSlice = extractSlice(NewData, S, Name);
1382 Type *StorableType = intrinsicTypeFor(SliceType);
1383 DataSlice = IRB.CreateBitCast(DataSlice, StorableType,
1384 DataSlice->
getName() +
".storable");
1388 NewSI->setOperand(0, DataSlice);
1389 NewSI->setOperand(1, NewPtr);
1392 return std::make_pair(
true,
false);
1395bool LegalizeBufferContentTypesVisitor::visitStoreInst(StoreInst &SI) {
1398 IRB.SetInsertPoint(&SI);
1399 SmallVector<uint32_t> AggIdxs;
1400 Value *OrigData =
SI.getValueOperand();
1401 auto [
Changed, ModifiedInPlace] =
1402 visitStoreImpl(SI, OrigData->
getType(), AggIdxs, 0, OrigData->
getName());
1403 if (
Changed && !ModifiedInPlace)
1404 SI.eraseFromParent();
1408bool LegalizeBufferContentTypesVisitor::visitAddrSpaceCastInst(
1409 AddrSpaceCastInst &AI) {
1414 auto Record = ZeroBasePointerToNumRecords.
find(Src);
1415 if (Record != ZeroBasePointerToNumRecords.
end())
1416 ZeroBasePointerToNumRecords.
insert({&AI,
Record->second});
1418 ZeroBasePointerToNumRecords.
insert({&AI,
nullptr});
1422bool LegalizeBufferContentTypesVisitor::visitIntrinsicInst(IntrinsicInst &
II) {
1423 if (
II.getIntrinsicID() != Intrinsic::amdgcn_make_buffer_rsrc)
1425 ZeroBasePointerToNumRecords.
insert({&
II,
II.getOperand(2)});
1429bool LegalizeBufferContentTypesVisitor::processFunction(
Function &
F,
1430 ScalarEvolution *SE) {
1437 ZeroBasePointerToNumRecords.
clear();
1444static std::pair<Constant *, Constant *>
1447 return std::make_pair(
C->getAggregateElement(0u),
C->getAggregateElement(1u));
1452class FatPtrConstMaterializer final :
public ValueMaterializer {
1453 BufferFatPtrToStructTypeMap *TypeMap;
1459 ValueMapper InternalMapper;
1461 Constant *materializeBufferFatPtrConst(Constant *
C);
1465 FatPtrConstMaterializer(BufferFatPtrToStructTypeMap *TypeMap,
1468 InternalMapper(UnderlyingMap,
RF_None, TypeMap, this) {}
1469 ~FatPtrConstMaterializer() =
default;
1475Constant *FatPtrConstMaterializer::materializeBufferFatPtrConst(Constant *
C) {
1476 Type *SrcTy =
C->getType();
1478 if (
C->isNullValue())
1479 return ConstantAggregateZero::getNullValue(NewTy);
1492 if (Constant *S =
VC->getSplatValue()) {
1497 auto EC =
VC->getType()->getElementCount();
1503 for (
Value *
Op :
VC->operand_values()) {
1518 "fat pointer) values are not supported");
1522 "constant exprs containing ptr addrspace(7) (buffer "
1523 "fat pointer) values should have been expanded earlier");
1528Value *FatPtrConstMaterializer::materialize(
Value *V) {
1536 return materializeBufferFatPtrConst(
C);
1544class SplitPtrStructs :
public InstVisitor<SplitPtrStructs, PtrParts> {
1587 void processConditionals();
1637void SplitPtrStructs::copyMetadata(
Value *Dest,
Value *Src) {
1641 if (!DestI || !SrcI)
1644 DestI->copyMetadata(*SrcI);
1649 "of something that wasn't rewritten");
1650 auto *RsrcEntry = &RsrcParts[
V];
1651 auto *OffEntry = &OffParts[
V];
1652 if (*RsrcEntry && *OffEntry)
1653 return {*RsrcEntry, *OffEntry};
1657 return {*RsrcEntry = Rsrc, *OffEntry =
Off};
1660 IRBuilder<InstSimplifyFolder>::InsertPointGuard Guard(IRB);
1665 return {*RsrcEntry = Rsrc, *OffEntry =
Off};
1668 IRB.SetInsertPoint(*
I->getInsertionPointAfterDef());
1669 IRB.SetCurrentDebugLocation(
I->getDebugLoc());
1671 IRB.SetInsertPointPastAllocas(
A->getParent());
1672 IRB.SetCurrentDebugLocation(
DebugLoc());
1674 Value *Rsrc = IRB.CreateExtractValue(V, 0,
V->getName() +
".rsrc");
1675 Value *
Off = IRB.CreateExtractValue(V, 1,
V->getName() +
".off");
1676 return {*RsrcEntry = Rsrc, *OffEntry =
Off};
1689 V =
GEP->getPointerOperand();
1691 V = ASC->getPointerOperand();
1695void SplitPtrStructs::getPossibleRsrcRoots(Instruction *
I,
1696 SmallPtrSetImpl<Value *> &Roots,
1697 SmallPtrSetImpl<Value *> &Seen) {
1701 for (
Value *In :
PHI->incoming_values()) {
1708 if (!Seen.
insert(SI).second)
1723void SplitPtrStructs::processConditionals() {
1724 SmallDenseMap<Value *, Value *> FoundRsrcs;
1725 SmallPtrSet<Value *, 4> Roots;
1726 SmallPtrSet<Value *, 4> Seen;
1727 for (Instruction *
I : Conditionals) {
1729 Value *Rsrc = RsrcParts[
I];
1731 assert(Rsrc && Off &&
"must have visited conditionals by now");
1733 std::optional<Value *> MaybeRsrc;
1734 auto MaybeFoundRsrc = FoundRsrcs.
find(
I);
1735 if (MaybeFoundRsrc != FoundRsrcs.
end()) {
1736 MaybeRsrc = MaybeFoundRsrc->second;
1738 IRBuilder<InstSimplifyFolder>::InsertPointGuard Guard(IRB);
1741 getPossibleRsrcRoots(
I, Roots, Seen);
1744 for (
Value *V : Roots)
1746 for (
Value *V : Seen)
1758 if (Diff.size() == 1) {
1759 Value *RootVal = *Diff.begin();
1763 MaybeRsrc = std::get<0>(getPtrParts(RootVal));
1765 MaybeRsrc = RootVal;
1773 IRB.SetInsertPoint(*
PHI->getInsertionPointAfterDef());
1774 IRB.SetCurrentDebugLocation(
PHI->getDebugLoc());
1776 NewRsrc = *MaybeRsrc;
1779 auto *RsrcPHI = IRB.CreatePHI(RsrcTy,
PHI->getNumIncomingValues());
1780 RsrcPHI->takeName(Rsrc);
1781 for (
auto [V, BB] :
llvm::zip(
PHI->incoming_values(),
PHI->blocks())) {
1782 Value *VRsrc = std::get<0>(getPtrParts(V));
1783 RsrcPHI->addIncoming(VRsrc, BB);
1785 copyMetadata(RsrcPHI,
PHI);
1790 auto *NewOff = IRB.CreatePHI(OffTy,
PHI->getNumIncomingValues());
1791 NewOff->takeName(Off);
1792 for (
auto [V, BB] :
llvm::zip(
PHI->incoming_values(),
PHI->blocks())) {
1793 assert(OffParts.
count(V) &&
"An offset part had to be created by now");
1794 Value *VOff = std::get<1>(getPtrParts(V));
1795 NewOff->addIncoming(VOff, BB);
1797 copyMetadata(NewOff,
PHI);
1807 RsrcInst->replaceAllUsesWith(NewRsrc);
1811 OffInst->replaceAllUsesWith(NewOff);
1816 for (
Value *V : Seen)
1817 FoundRsrcs[
V] = NewRsrc;
1822 if (RsrcInst != *MaybeRsrc) {
1824 RsrcInst->replaceAllUsesWith(*MaybeRsrc);
1827 for (
Value *V : Seen)
1828 FoundRsrcs[
V] = *MaybeRsrc;
1836void SplitPtrStructs::killAndReplaceSplitInstructions(
1837 SmallVectorImpl<Instruction *> &Origs) {
1838 for (Instruction *
I : ConditionalTemps)
1839 I->eraseFromParent();
1841 for (Instruction *
I : Origs) {
1847 for (DbgVariableRecord *Dbg : Dbgs) {
1848 auto &
DL =
I->getDataLayout();
1850 "We should've RAUW'd away loads, stores, etc. at this point");
1851 DbgVariableRecord *OffDbg =
Dbg->clone();
1852 auto [Rsrc,
Off] = getPtrParts(
I);
1854 int64_t RsrcSz =
DL.getTypeSizeInBits(Rsrc->
getType());
1855 int64_t OffSz =
DL.getTypeSizeInBits(
Off->getType());
1857 std::optional<DIExpression *> RsrcExpr =
1860 std::optional<DIExpression *> OffExpr =
1871 Dbg->setExpression(*RsrcExpr);
1872 Dbg->replaceVariableLocationOp(
I, Rsrc);
1879 I->replaceUsesWithIf(
Poison, [&](
const Use &U) ->
bool {
1885 if (
I->use_empty()) {
1886 I->eraseFromParent();
1889 IRB.SetInsertPoint(*
I->getInsertionPointAfterDef());
1890 IRB.SetCurrentDebugLocation(
I->getDebugLoc());
1891 auto [Rsrc,
Off] = getPtrParts(
I);
1893 Struct = IRB.CreateInsertValue(Struct, Rsrc, 0);
1894 Struct = IRB.CreateInsertValue(Struct, Off, 1);
1895 copyMetadata(Struct,
I);
1897 I->replaceAllUsesWith(Struct);
1898 I->eraseFromParent();
1902void SplitPtrStructs::setAlign(CallInst *Intr, Align
A,
unsigned RsrcArgIdx) {
1904 Intr->
addParamAttr(RsrcArgIdx, Attribute::getWithAlignment(Ctx,
A));
1910 case AtomicOrdering::Release:
1911 case AtomicOrdering::AcquireRelease:
1912 case AtomicOrdering::SequentiallyConsistent:
1913 IRB.CreateFence(AtomicOrdering::Release, SSID);
1923 case AtomicOrdering::Acquire:
1924 case AtomicOrdering::AcquireRelease:
1925 case AtomicOrdering::SequentiallyConsistent:
1926 IRB.CreateFence(AtomicOrdering::Acquire, SSID);
1933Value *SplitPtrStructs::handleMemoryInst(Instruction *
I,
Value *Arg,
Value *Ptr,
1934 Type *Ty, Align Alignment,
1937 IRB.SetInsertPoint(
I);
1939 auto [Rsrc,
Off] = getPtrParts(Ptr);
1942 Args.push_back(Arg);
1943 Args.push_back(Rsrc);
1944 Args.push_back(Off);
1945 insertPreMemOpFence(Order, SSID);
1949 Args.push_back(IRB.getInt32(0));
1954 Args.push_back(IRB.getInt32(Aux));
1958 IID = Order == AtomicOrdering::NotAtomic
1959 ? Intrinsic::amdgcn_raw_ptr_buffer_load
1960 : Intrinsic::amdgcn_raw_ptr_atomic_buffer_load;
1962 IID = Intrinsic::amdgcn_raw_ptr_buffer_store;
1964 switch (RMW->getOperation()) {
1966 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_swap;
1969 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_add;
1972 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_sub;
1975 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_and;
1978 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_or;
1981 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_xor;
1984 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_smax;
1987 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_smin;
1990 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_umax;
1993 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_umin;
1996 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_fadd;
1999 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_fmax;
2002 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_fmin;
2005 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_cond_sub_u32;
2008 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_sub_clamp_u32;
2012 "atomic floating point subtraction not supported for "
2013 "buffer resources and should've been expanded away");
2018 "atomic floating point fmaximum not supported for "
2019 "buffer resources and should've been expanded away");
2024 "atomic floating point fminimum not supported for "
2025 "buffer resources and should've been expanded away");
2030 "atomic floating point fmaximumnum not supported for "
2031 "buffer resources and should've been expanded away");
2036 "atomic floating point fminimumnum not supported for "
2037 "buffer resources and should've been expanded away");
2042 "atomic nand not supported for buffer resources and "
2043 "should've been expanded away");
2048 "wrapping increment/decrement not supported for "
2049 "buffer resources and should've been expanded away");
2056 CallInst *
Call = IRB.CreateIntrinsicWithoutFolding(IID, Ty, Args);
2057 copyMetadata(
Call,
I);
2058 setAlign(
Call, Alignment, Arg ? 1 : 0);
2061 insertPostMemOpFence(Order, SSID);
2065 I->replaceAllUsesWith(
Call);
2069PtrParts SplitPtrStructs::visitInstruction(Instruction &
I) {
2070 return {
nullptr,
nullptr};
2073PtrParts SplitPtrStructs::visitLoadInst(LoadInst &LI) {
2075 return {
nullptr,
nullptr};
2079 return {
nullptr,
nullptr};
2082PtrParts SplitPtrStructs::visitStoreInst(StoreInst &SI) {
2084 return {
nullptr,
nullptr};
2085 Value *Arg =
SI.getValueOperand();
2086 handleMemoryInst(&SI, Arg,
SI.getPointerOperand(), Arg->
getType(),
2087 SI.getAlign(),
SI.getOrdering(),
SI.isVolatile(),
2088 SI.getSyncScopeID());
2089 return {
nullptr,
nullptr};
2092PtrParts SplitPtrStructs::visitAtomicRMWInst(AtomicRMWInst &AI) {
2094 return {
nullptr,
nullptr};
2099 return {
nullptr,
nullptr};
2104PtrParts SplitPtrStructs::visitAtomicCmpXchgInst(AtomicCmpXchgInst &AI) {
2107 return {
nullptr,
nullptr};
2108 IRB.SetInsertPoint(&AI);
2113 bool IsNonTemporal = AI.
getMetadata(LLVMContext::MD_nontemporal);
2115 auto [Rsrc,
Off] = getPtrParts(Ptr);
2116 insertPreMemOpFence(Order, SSID);
2123 CallInst *
Call = IRB.CreateIntrinsicWithoutFolding(
2124 Intrinsic::amdgcn_raw_ptr_buffer_atomic_cmpswap, Ty,
2126 IRB.getInt32(0), IRB.getInt32(Aux)});
2127 copyMetadata(
Call, &AI);
2130 insertPostMemOpFence(Order, SSID);
2133 Res = IRB.CreateInsertValue(Res,
Call, 0);
2135 Res = IRB.CreateInsertValue(Res, Succeeded, 1);
2138 return {
nullptr,
nullptr};
2141PtrParts SplitPtrStructs::visitGetElementPtrInst(GetElementPtrInst &
GEP) {
2142 using namespace llvm::PatternMatch;
2143 Value *Ptr =
GEP.getPointerOperand();
2145 return {
nullptr,
nullptr};
2146 IRB.SetInsertPoint(&
GEP);
2148 auto [Rsrc,
Off] = getPtrParts(Ptr);
2149 const DataLayout &
DL =
GEP.getDataLayout();
2150 bool IsNUW =
GEP.hasNoUnsignedWrap();
2151 bool IsNUSW =
GEP.hasNoUnsignedSignedWrap();
2162 GEP.mutateType(FatPtrTy);
2164 GEP.mutateType(ResTy);
2166 if (BroadcastsPtr) {
2167 Rsrc = IRB.CreateVectorSplat(ResRsrcVecTy->getElementCount(), Rsrc,
2169 Off = IRB.CreateVectorSplat(ResRsrcVecTy->getElementCount(), Off,
2177 bool HasNonNegativeOff =
false;
2179 HasNonNegativeOff = !CI->isNegative();
2185 NewOff = IRB.CreateAdd(Off, OffAccum,
"",
2186 IsNUW || (IsNUSW && HasNonNegativeOff),
2189 copyMetadata(NewOff, &
GEP);
2192 return {Rsrc, NewOff};
2195PtrParts SplitPtrStructs::visitPtrToIntInst(PtrToIntInst &PI) {
2198 return {
nullptr,
nullptr};
2199 IRB.SetInsertPoint(&PI);
2204 auto [Rsrc,
Off] = getPtrParts(Ptr);
2210 Res = IRB.CreateIntCast(Off, ResTy,
false,
2213 Value *RsrcInt = IRB.CreatePtrToInt(Rsrc, ResTy, PI.
getName() +
".rsrc");
2214 Value *Shl = IRB.CreateShl(
2217 "", Width >= FatPtrWidth, Width > FatPtrWidth);
2218 Value *OffCast = IRB.CreateIntCast(Off, ResTy,
false,
2220 Res = IRB.CreateOr(Shl, OffCast);
2223 copyMetadata(Res, &PI);
2227 return {
nullptr,
nullptr};
2230PtrParts SplitPtrStructs::visitPtrToAddrInst(PtrToAddrInst &PA) {
2233 return {
nullptr,
nullptr};
2234 IRB.SetInsertPoint(&PA);
2236 auto [Rsrc,
Off] = getPtrParts(Ptr);
2237 Value *Res = IRB.CreateIntCast(Off, PA.
getType(),
false);
2238 copyMetadata(Res, &PA);
2242 return {
nullptr,
nullptr};
2245PtrParts SplitPtrStructs::visitIntToPtrInst(IntToPtrInst &IP) {
2247 return {
nullptr,
nullptr};
2248 IRB.SetInsertPoint(&IP);
2257 Type *RsrcTy = RetTy->getElementType(0);
2258 Type *OffTy = RetTy->getElementType(1);
2267 RsrcInt = IRB.CreateIntCast(RsrcPart, RsrcIntTy,
false);
2269 Value *Rsrc = IRB.CreateIntToPtr(RsrcInt, RsrcTy, IP.
getName() +
".rsrc");
2271 IRB.CreateIntCast(
Int, OffTy,
false, IP.
getName() +
".off");
2273 copyMetadata(Rsrc, &IP);
2278PtrParts SplitPtrStructs::visitAddrSpaceCastInst(AddrSpaceCastInst &
I) {
2282 return {
nullptr,
nullptr};
2283 IRB.SetInsertPoint(&
I);
2286 if (
In->getType() ==
I.getType()) {
2287 auto [Rsrc,
Off] = getPtrParts(In);
2293 Type *RsrcTy = ResTy->getElementType(0);
2294 Type *OffTy = ResTy->getElementType(1);
2300 if (InConst && InConst->isNullValue()) {
2303 return {NullRsrc, ZeroOff};
2309 return {PoisonRsrc, PoisonOff};
2315 return {UndefRsrc, UndefOff};
2320 "only buffer resources (addrspace 8) and null/poison pointers can be "
2321 "cast to buffer fat pointers (addrspace 7)");
2323 return {
In, ZeroOff};
2326PtrParts SplitPtrStructs::visitICmpInst(ICmpInst &Cmp) {
2329 return {
nullptr,
nullptr};
2331 IRB.SetInsertPoint(&Cmp);
2332 ICmpInst::Predicate Pred =
Cmp.getPredicate();
2334 assert((Pred == ICmpInst::ICMP_EQ || Pred == ICmpInst::ICMP_NE) &&
2335 "Pointer comparison is only equal or unequal");
2336 auto [LhsRsrc, LhsOff] = getPtrParts(Lhs);
2337 auto [RhsRsrc, RhsOff] = getPtrParts(Rhs);
2338 Value *Res = IRB.CreateICmp(Pred, LhsOff, RhsOff);
2339 copyMetadata(Res, &Cmp);
2342 Cmp.replaceAllUsesWith(Res);
2343 return {
nullptr,
nullptr};
2346PtrParts SplitPtrStructs::visitFreezeInst(FreezeInst &
I) {
2348 return {
nullptr,
nullptr};
2349 IRB.SetInsertPoint(&
I);
2350 auto [Rsrc,
Off] = getPtrParts(
I.getOperand(0));
2352 Value *RsrcRes = IRB.CreateFreeze(Rsrc,
I.getName() +
".rsrc");
2353 copyMetadata(RsrcRes, &
I);
2354 Value *OffRes = IRB.CreateFreeze(Off,
I.getName() +
".off");
2355 copyMetadata(OffRes, &
I);
2357 return {RsrcRes, OffRes};
2360PtrParts SplitPtrStructs::visitExtractElementInst(ExtractElementInst &
I) {
2362 return {
nullptr,
nullptr};
2363 IRB.SetInsertPoint(&
I);
2364 Value *Vec =
I.getVectorOperand();
2365 Value *Idx =
I.getIndexOperand();
2366 auto [Rsrc,
Off] = getPtrParts(Vec);
2368 Value *RsrcRes = IRB.CreateExtractElement(Rsrc, Idx,
I.getName() +
".rsrc");
2369 copyMetadata(RsrcRes, &
I);
2370 Value *OffRes = IRB.CreateExtractElement(Off, Idx,
I.getName() +
".off");
2371 copyMetadata(OffRes, &
I);
2373 return {RsrcRes, OffRes};
2376PtrParts SplitPtrStructs::visitInsertElementInst(InsertElementInst &
I) {
2380 return {
nullptr,
nullptr};
2381 IRB.SetInsertPoint(&
I);
2382 Value *Vec =
I.getOperand(0);
2383 Value *Elem =
I.getOperand(1);
2384 Value *Idx =
I.getOperand(2);
2385 auto [VecRsrc, VecOff] = getPtrParts(Vec);
2386 auto [ElemRsrc, ElemOff] = getPtrParts(Elem);
2389 IRB.CreateInsertElement(VecRsrc, ElemRsrc, Idx,
I.getName() +
".rsrc");
2390 copyMetadata(RsrcRes, &
I);
2392 IRB.CreateInsertElement(VecOff, ElemOff, Idx,
I.getName() +
".off");
2393 copyMetadata(OffRes, &
I);
2395 return {RsrcRes, OffRes};
2398PtrParts SplitPtrStructs::visitShuffleVectorInst(ShuffleVectorInst &
I) {
2401 return {
nullptr,
nullptr};
2402 IRB.SetInsertPoint(&
I);
2405 Value *V2 =
I.getOperand(1);
2406 ArrayRef<int>
Mask =
I.getShuffleMask();
2407 auto [V1Rsrc, V1Off] = getPtrParts(
V1);
2408 auto [V2Rsrc, V2Off] = getPtrParts(V2);
2411 IRB.CreateShuffleVector(V1Rsrc, V2Rsrc, Mask,
I.getName() +
".rsrc");
2412 copyMetadata(RsrcRes, &
I);
2414 IRB.CreateShuffleVector(V1Off, V2Off, Mask,
I.getName() +
".off");
2415 copyMetadata(OffRes, &
I);
2417 return {RsrcRes, OffRes};
2420PtrParts SplitPtrStructs::visitPHINode(PHINode &
PHI) {
2422 return {
nullptr,
nullptr};
2423 IRB.SetInsertPoint(*
PHI.getInsertionPointAfterDef());
2429 Value *TmpRsrc = IRB.CreateExtractValue(&
PHI, 0,
PHI.getName() +
".rsrc");
2430 Value *TmpOff = IRB.CreateExtractValue(&
PHI, 1,
PHI.getName() +
".off");
2431 Conditionals.push_back(&
PHI);
2433 return {TmpRsrc, TmpOff};
2436PtrParts SplitPtrStructs::visitSelectInst(SelectInst &SI) {
2438 return {
nullptr,
nullptr};
2439 IRB.SetInsertPoint(&SI);
2442 Value *True =
SI.getTrueValue();
2443 Value *False =
SI.getFalseValue();
2444 auto [TrueRsrc, TrueOff] = getPtrParts(True);
2445 auto [FalseRsrc, FalseOff] = getPtrParts(False);
2448 IRB.CreateSelect(
Cond, TrueRsrc, FalseRsrc,
SI.getName() +
".rsrc", &SI);
2449 copyMetadata(RsrcRes, &SI);
2450 Conditionals.push_back(&SI);
2452 IRB.CreateSelect(
Cond, TrueOff, FalseOff,
SI.getName() +
".off", &SI);
2453 copyMetadata(OffRes, &SI);
2455 return {RsrcRes, OffRes};
2466 case Intrinsic::amdgcn_make_buffer_rsrc:
2467 case Intrinsic::ptrmask:
2468 case Intrinsic::invariant_start:
2469 case Intrinsic::invariant_end:
2470 case Intrinsic::launder_invariant_group:
2471 case Intrinsic::strip_invariant_group:
2472 case Intrinsic::memcpy:
2473 case Intrinsic::memcpy_inline:
2474 case Intrinsic::memmove:
2475 case Intrinsic::memset:
2476 case Intrinsic::memset_inline:
2477 case Intrinsic::experimental_memset_pattern:
2478 case Intrinsic::amdgcn_load_to_lds:
2479 case Intrinsic::amdgcn_load_async_to_lds:
2484PtrParts SplitPtrStructs::visitIntrinsicInst(IntrinsicInst &
I) {
2489 case Intrinsic::amdgcn_make_buffer_rsrc: {
2491 return {
nullptr,
nullptr};
2493 Value *Stride =
I.getArgOperand(1);
2494 Value *NumRecords =
I.getArgOperand(2);
2497 Type *RsrcType = SplitType->getElementType(0);
2498 Type *OffType = SplitType->getElementType(1);
2499 IRB.SetInsertPoint(&
I);
2500 Value *Rsrc = IRB.CreateIntrinsic(
2501 IID, {RsrcType,
Base->getType(), NumRecords->
getType()},
2503 copyMetadata(Rsrc, &
I);
2507 return {Rsrc,
Zero};
2509 case Intrinsic::ptrmask: {
2510 Value *Ptr =
I.getArgOperand(0);
2512 return {
nullptr,
nullptr};
2514 IRB.SetInsertPoint(&
I);
2515 auto [Rsrc,
Off] = getPtrParts(Ptr);
2516 if (
Mask->getType() !=
Off->getType())
2518 "pointer (data layout not set up correctly?)");
2519 Value *OffRes = IRB.CreateAnd(Off, Mask,
I.getName() +
".off");
2520 copyMetadata(OffRes, &
I);
2522 return {Rsrc, OffRes};
2526 case Intrinsic::invariant_start: {
2527 Value *Ptr =
I.getArgOperand(1);
2529 return {
nullptr,
nullptr};
2530 IRB.SetInsertPoint(&
I);
2531 auto [Rsrc,
Off] = getPtrParts(Ptr);
2533 auto *NewRsrc = IRB.CreateIntrinsic(IID, {NewTy}, {
I.getOperand(0), Rsrc});
2534 copyMetadata(NewRsrc, &
I);
2537 I.replaceAllUsesWith(NewRsrc);
2538 return {
nullptr,
nullptr};
2540 case Intrinsic::invariant_end: {
2541 Value *RealPtr =
I.getArgOperand(2);
2543 return {
nullptr,
nullptr};
2544 IRB.SetInsertPoint(&
I);
2545 Value *RealRsrc = getPtrParts(RealPtr).first;
2546 Value *InvPtr =
I.getArgOperand(0);
2548 Value *NewRsrc = IRB.CreateIntrinsic(IID, {RealRsrc->
getType()},
2549 {InvPtr,
Size, RealRsrc});
2550 copyMetadata(NewRsrc, &
I);
2553 I.replaceAllUsesWith(NewRsrc);
2554 return {
nullptr,
nullptr};
2556 case Intrinsic::launder_invariant_group:
2557 case Intrinsic::strip_invariant_group: {
2558 Value *Ptr =
I.getArgOperand(0);
2560 return {
nullptr,
nullptr};
2561 IRB.SetInsertPoint(&
I);
2562 auto [Rsrc,
Off] = getPtrParts(Ptr);
2563 Value *NewRsrc = IRB.CreateIntrinsic(IID, {Rsrc->
getType()}, {Rsrc});
2564 copyMetadata(NewRsrc, &
I);
2567 return {NewRsrc,
Off};
2569 case Intrinsic::amdgcn_load_to_lds:
2570 case Intrinsic::amdgcn_load_async_to_lds: {
2571 Value *Ptr =
I.getArgOperand(0);
2573 return {
nullptr,
nullptr};
2574 IRB.SetInsertPoint(&
I);
2575 auto [Rsrc,
Off] = getPtrParts(Ptr);
2576 Value *LDSPtr =
I.getArgOperand(1);
2577 Value *LoadSize =
I.getArgOperand(2);
2578 Value *ImmOff =
I.getArgOperand(3);
2579 Value *Aux =
I.getArgOperand(4);
2580 Value *SOffset = IRB.getInt32(0);
2582 IID == Intrinsic::amdgcn_load_to_lds
2583 ? Intrinsic::amdgcn_raw_ptr_buffer_load_lds
2584 : Intrinsic::amdgcn_raw_ptr_buffer_load_async_lds;
2585 Instruction *NewLoad = IRB.CreateIntrinsicWithoutFolding(
2586 NewIntr, {}, {Rsrc, LDSPtr, LoadSize,
Off, SOffset, ImmOff, Aux});
2587 copyMetadata(NewLoad, &
I);
2589 I.replaceAllUsesWith(NewLoad);
2590 return {
nullptr,
nullptr};
2593 return {
nullptr,
nullptr};
2596void SplitPtrStructs::processFunction(
Function &
F) {
2598 SmallVector<Instruction *, 0> Originals(
2600 LLVM_DEBUG(
dbgs() <<
"Splitting pointer structs in function: " <<
F.getName()
2602 for (Instruction *
I : Originals) {
2610 assert(((Rsrc && Off) || (!Rsrc && !Off)) &&
2611 "Can't have a resource but no offset");
2613 RsrcParts[
I] = Rsrc;
2617 processConditionals();
2618 killAndReplaceSplitInstructions(Originals);
2624 Conditionals.clear();
2625 ConditionalTemps.clear();
2629class AMDGPULowerBufferFatPointers :
public ModulePass {
2633 AMDGPULowerBufferFatPointers() : ModulePass(
ID) {}
2636 bool runOnModule(
Module &M)
override;
2638 void getAnalysisUsage(AnalysisUsage &AU)
const override;
2646 BufferFatPtrToStructTypeMap *TypeMap) {
2647 bool HasFatPointers =
false;
2650 HasFatPointers |= (
I.getType() != TypeMap->remapType(
I.getType()));
2652 for (
const Value *V :
I.operand_values())
2653 HasFatPointers |= (V->getType() != TypeMap->remapType(V->getType()));
2655 return HasFatPointers;
2659 BufferFatPtrToStructTypeMap *TypeMap) {
2660 Type *Ty =
F.getFunctionType();
2661 return Ty != TypeMap->remapType(Ty);
2677 while (!OldF->
empty()) {
2691 CloneMap[&NewArg] = &OldArg;
2692 NewArg.takeName(&OldArg);
2693 Type *OldArgTy = OldArg.getType(), *NewArgTy = NewArg.getType();
2695 NewArg.mutateType(OldArgTy);
2696 OldArg.replaceAllUsesWith(&NewArg);
2697 NewArg.mutateType(NewArgTy);
2701 if (OldArgTy != NewArgTy && !IsIntrinsic)
2704 AttributeFuncs::typeIncompatible(NewArgTy, ArgAttr));
2711 AttributeFuncs::typeIncompatible(NewF->
getReturnType(), RetAttrs));
2713 NewF->
getContext(), OldAttrs.getFnAttrs(), RetAttrs, ArgAttrs));
2721 CloneMap[&BB] = &BB;
2727bool AMDGPULowerBufferFatPointers::run(
Module &M,
const TargetMachine &TM,
2730 const DataLayout &
DL =
M.getDataLayout();
2736 LLVMContext &Ctx =
M.getContext();
2738 BufferFatPtrToStructTypeMap StructTM(
DL);
2739 BufferFatPtrToIntTypeMap IntTM(
DL);
2743 Ctx.
emitError(
"global variables with a buffer fat pointer address "
2744 "space (7) are not supported");
2746 GV.eraseFromParent();
2751 Type *VT = GV.getValueType();
2752 if (VT != StructTM.remapType(VT)) {
2754 Ctx.
emitError(
"global variables that contain buffer fat pointers "
2755 "(address space 7 pointers) are unsupported. Use "
2756 "buffer resource pointers (address space 8) instead");
2758 GV.eraseFromParent();
2774 SmallPtrSet<Constant *, 8> Visited;
2775 SetVector<Constant *> BufferFatPtrConsts;
2776 while (!Worklist.
empty()) {
2778 if (!Visited.
insert(
C).second)
2794 StoreFatPtrsAsIntsAndExpandMemcpyVisitor MemOpsRewrite(&IntTM,
DL,
2796 LegalizeBufferContentTypesVisitor BufferContentsTypeRewrite(
2797 DL,
M.getContext(), &TM);
2801 const TargetTransformInfo *
TTI = GetTTI(
F);
2802 ScalarEvolution *SE = GetSE(
F);
2803 Changed |= MemOpsRewrite.processFunction(
F,
TTI, SE);
2804 if (InterfaceChange || BodyChanges) {
2805 NeedsRemap.
push_back(std::make_pair(&
F, InterfaceChange));
2806 Changed |= BufferContentsTypeRewrite.processFunction(
F, SE);
2809 if (NeedsRemap.
empty())
2816 FatPtrConstMaterializer Materializer(&StructTM, CloneMap);
2818 ValueMapper LowerInFuncs(CloneMap,
RF_None, &StructTM, &Materializer);
2819 for (
auto [
F, InterfaceChange] : NeedsRemap) {
2821 if (InterfaceChange)
2827 LowerInFuncs.remapFunction(*NewF);
2832 if (InterfaceChange) {
2833 F->replaceAllUsesWith(NewF);
2834 F->eraseFromParent();
2842 SplitPtrStructs Splitter(
DL,
M.getContext(), &TM);
2844 Splitter.processFunction(*
F);
2849 F->eraseFromParent();
2853 F->replaceAllUsesWith(*NewF);
2859bool AMDGPULowerBufferFatPointers::runOnModule(
Module &M) {
2860 TargetPassConfig &TPC = getAnalysis<TargetPassConfig>();
2861 const TargetMachine &TM = TPC.
getTM<TargetMachine>();
2862 auto GetTTI = [&](
Function &
F) ->
const TargetTransformInfo * {
2863 if (
F.isDeclaration())
2865 return &getAnalysis<TargetTransformInfoWrapperPass>().getTTI(
F);
2867 auto GetSE = [&](
Function &
F) -> ScalarEvolution * {
2868 if (
F.isDeclaration())
2870 return &getAnalysis<ScalarEvolutionWrapperPass>(
F).getSE();
2872 return run(M, TM, GetTTI, GetSE);
2875char AMDGPULowerBufferFatPointers::ID = 0;
2879void AMDGPULowerBufferFatPointers::getAnalysisUsage(
AnalysisUsage &AU)
const {
2885#define PASS_DESC "Lower buffer fat pointer operations to buffer resources"
2896 return new AMDGPULowerBufferFatPointers();
2903 if (
F.isDeclaration())
2908 if (
F.isDeclaration())
2912 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)
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.
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 bool isFixed() const
Returns true if the quantity is not scaled by vscale.
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.
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.