243#include "llvm/IR/IntrinsicsAMDGPU.h"
263#define DEBUG_TYPE "amdgpu-lower-buffer-fat-pointers"
288 Type *remapType(
Type *SrcTy)
override;
289 void clear() { Map.clear(); }
295class BufferFatPtrToIntTypeMap :
public BufferFatPtrTypeLoweringBase {
296 using BufferFatPtrTypeLoweringBase::BufferFatPtrTypeLoweringBase;
306class BufferFatPtrToStructTypeMap :
public BufferFatPtrTypeLoweringBase {
307 using BufferFatPtrTypeLoweringBase::BufferFatPtrTypeLoweringBase;
316Type *BufferFatPtrTypeLoweringBase::remapTypeImpl(
Type *Ty) {
322 return *
Entry = remapScalar(PT);
328 return *
Entry = remapVector(VT);
336 bool IsUniqued = !TyAsStruct || TyAsStruct->
isLiteral();
345 Type *NewElem = remapTypeImpl(OldElem);
346 ElementTypes[
I] = NewElem;
347 Changed |= (OldElem != NewElem);
355 return *
Entry = ArrayType::get(ElementTypes[0], ArrTy->getNumElements());
357 return *
Entry = FunctionType::get(ElementTypes[0],
367 SmallString<16>
Name(STy->getName());
375Type *BufferFatPtrTypeLoweringBase::remapType(
Type *SrcTy) {
376 return remapTypeImpl(SrcTy);
379Type *BufferFatPtrToStructTypeMap::remapScalar(PointerType *PT) {
380 LLVMContext &Ctx = PT->getContext();
385Type *BufferFatPtrToStructTypeMap::remapVector(VectorType *VT) {
386 ElementCount
EC = VT->getElementCount();
387 LLVMContext &Ctx = VT->getContext();
406 if (!ST->isLiteral() || ST->getNumElements() != 2)
412 return MaybeRsrc && MaybeOff &&
421 return isBufferFatPtrOrVector(U.get()->getType());
434class StoreFatPtrsAsIntsAndExpandMemcpyVisitor
435 :
public InstVisitor<StoreFatPtrsAsIntsAndExpandMemcpyVisitor, bool> {
436 BufferFatPtrToIntTypeMap *TypeMap;
440 const DataLayout &
DL;
443 const TargetTransformInfo *
TTI;
450 Type *Ty, SmallVectorImpl<unsigned> &AggIdxs,
uint64_t Off,
452 function_ref<
void(
Type *LeafTy,
Type *IntLeafTy, ArrayRef<unsigned> Idxs,
457 StoreFatPtrsAsIntsAndExpandMemcpyVisitor(BufferFatPtrToIntTypeMap *TypeMap,
458 const DataLayout &
DL,
460 : TypeMap(TypeMap), IRB(Ctx, InstSimplifyFolder(
DL)),
DL(
DL) {}
462 ScalarEvolution *SE);
464 bool visitInstruction(Instruction &
I) {
return false; }
465 bool visitAllocaInst(AllocaInst &
I);
466 bool visitLoadInst(LoadInst &LI);
467 bool visitStoreInst(StoreInst &SI);
468 bool visitGetElementPtrInst(GetElementPtrInst &
I);
470 bool visitMemCpyInst(MemCpyInst &MCI);
471 bool visitMemMoveInst(MemMoveInst &MMI);
472 bool visitMemSetInst(MemSetInst &MSI);
473 bool visitMemSetPatternInst(MemSetPatternInst &MSPI);
477Value *StoreFatPtrsAsIntsAndExpandMemcpyVisitor::applyOffset(
Value *Ptr,
480 return IRB.CreatePtrAdd(
481 Ptr, ConstantInt::get(
DL.getIndexType(Ptr->
getType()), Off),
485void StoreFatPtrsAsIntsAndExpandMemcpyVisitor::forEachAggLeaf(
486 Type *Ty, SmallVectorImpl<unsigned> &AggIdxs,
uint64_t Off,
488 function_ref<
void(
Type *LeafTy,
Type *IntLeafTy, ArrayRef<unsigned> Idxs,
491 Type *IntTy = TypeMap->remapType(Ty);
494 if (
DL.getTypeStoreSize(Ty) != 0)
495 Visit(Ty, IntTy, AggIdxs, Off, Name);
498 auto Recurse = [&](
unsigned I,
Type *ElemTy,
uint64_t ElemOff) {
500 forEachAggLeaf(ElemTy, AggIdxs, Off + ElemOff, Name +
"." + Twine(
I),
505 const StructLayout *Layout =
DL.getStructLayout(ST);
506 for (
auto [
I, ElemTy, ElemOff] :
508 Recurse(
I, ElemTy, ElemOff.getFixedValue());
512 Type *ElemTy = AT->getElementType();
513 uint64_t Stride =
DL.getTypeAllocSize(ElemTy).getFixedValue();
515 Recurse(
I, ElemTy,
I * Stride);
518bool StoreFatPtrsAsIntsAndExpandMemcpyVisitor::processFunction(
519 Function &
F,
const TargetTransformInfo *
TTI, ScalarEvolution *SE) {
540bool StoreFatPtrsAsIntsAndExpandMemcpyVisitor::visitAllocaInst(AllocaInst &
I) {
541 Type *Ty =
I.getAllocatedType();
542 Type *NewTy = TypeMap->remapType(Ty);
547 TypeSize AllocSize =
DL.getTypeAllocSize(Ty);
548 if (AllocSize.
isFixed() &&
DL.getTypeAllocSize(NewTy) != AllocSize)
549 NewTy = ArrayType::get(IRB.getInt8Ty(), AllocSize.
getFixedValue());
550 I.setAllocatedType(NewTy);
554bool StoreFatPtrsAsIntsAndExpandMemcpyVisitor::visitGetElementPtrInst(
555 GetElementPtrInst &
I) {
556 Type *Ty =
I.getSourceElementType();
557 if (Ty == TypeMap->remapType(Ty))
561 IRB.SetInsertPoint(&
I);
563 Value *NewGEP = IRB.CreatePtrAdd(
I.getPointerOperand(), Off,
I.getName(),
565 I.replaceAllUsesWith(NewGEP);
570bool StoreFatPtrsAsIntsAndExpandMemcpyVisitor::visitLoadInst(LoadInst &LI) {
572 Type *IntTy = TypeMap->remapType(Ty);
576 IRB.SetInsertPoint(&LI);
582 SmallVector<unsigned> AggIdxs;
585 [&](
Type *LeafTy,
Type *IntLeafTy, ArrayRef<unsigned> Idxs,
587 Value *Ptr = applyOffset(LI.getPointerOperand(), Off);
588 LoadInst *NewLI = IRB.CreateAlignedLoad(
589 IntLeafTy, Ptr, commonAlignment(LI.getAlign(), Off), Name);
590 NewLI->setVolatile(LI.isVolatile());
591 copyMetadataForLoad(*NewLI, LI);
592 NewLI->setAAMetadata(AATags.adjustForAccess(Off, IntLeafTy, DL));
594 if (LeafTy != IntLeafTy)
595 V = IRB.CreateIntToPtr(NewLI, LeafTy, Name +
".ptr");
596 Agg = IRB.CreateInsertValue(Agg, V, Idxs, Name +
".agg");
603 NLI->mutateType(IntTy);
604 NLI = IRB.Insert(NLI);
607 Value *CastBack = IRB.CreateIntToPtr(NLI, Ty, NLI->getName() +
".ptr");
613bool StoreFatPtrsAsIntsAndExpandMemcpyVisitor::visitStoreInst(StoreInst &SI) {
615 Type *Ty =
V->getType();
616 Type *IntTy = TypeMap->remapType(Ty);
620 IRB.SetInsertPoint(&SI);
624 AAMDNodes AATags =
SI.getAAMetadata();
625 SmallVector<unsigned> AggIdxs;
627 Ty, AggIdxs, 0,
V->getName(),
628 [&](
Type *LeafTy,
Type *IntLeafTy, ArrayRef<unsigned> Idxs,
630 Value *Leaf = IRB.CreateExtractValue(V, Idxs, Name);
631 if (LeafTy != IntLeafTy)
632 Leaf = IRB.CreatePtrToInt(Leaf, IntLeafTy, Name +
".int");
633 auto *NewSI = cast<StoreInst>(SI.clone());
634 NewSI->setAlignment(commonAlignment(SI.getAlign(), Off));
635 NewSI->setOperand(0, Leaf);
636 NewSI->setOperand(1, applyOffset(SI.getPointerOperand(), Off));
638 NewSI->setMetadata(LLVMContext::MD_DIAssignID, nullptr);
640 NewSI->setAAMetadata(AATags.adjustForAccess(Off, IntLeafTy, DL));
642 SI.eraseFromParent();
645 Value *IntV = IRB.CreatePtrToInt(V, IntTy,
V->getName() +
".int");
649 SI.setOperand(0, IntV);
653bool StoreFatPtrsAsIntsAndExpandMemcpyVisitor::visitMemCpyInst(
665bool StoreFatPtrsAsIntsAndExpandMemcpyVisitor::visitMemMoveInst(
671 "memmove() on buffer descriptors is not implemented because pointer "
672 "comparison on buffer descriptors isn't implemented\n");
675bool StoreFatPtrsAsIntsAndExpandMemcpyVisitor::visitMemSetInst(
684bool StoreFatPtrsAsIntsAndExpandMemcpyVisitor::visitMemSetPatternInst(
685 MemSetPatternInst &MSPI) {
714class LegalizeBufferContentTypesVisitor
715 :
public InstVisitor<LegalizeBufferContentTypesVisitor, bool> {
716 friend class InstVisitor<LegalizeBufferContentTypesVisitor, bool>;
720 const DataLayout &
DL;
722 ScalarEvolution *SE =
nullptr;
732 const TargetMachine *TM;
733 const GCNSubtarget *ST =
nullptr;
737 Type *scalarArrayTypeAsVector(
Type *MaybeArrayType);
738 Value *arrayToVector(
Value *V,
Type *TargetType,
const Twine &Name);
739 Value *vectorToArray(
Value *V,
Type *OrigType,
const Twine &Name);
743 struct OobProperties {
745 bool NoWrapFromMax =
false;
747 bool NoPartialOOB =
false;
749 OobProperties() =
delete;
751 OobProperties(
bool NoWrapFromMax,
bool NoPartialOOB)
752 : NoWrapFromMax(NoWrapFromMax), NoPartialOOB(NoPartialOOB) {}
782 uint64_t maxIntrinsicWidth(
Type *Ty, Align
A, OobProperties OobProps);
789 Value *makeLegalNonAggregate(
Value *V,
Type *TargetType,
const Twine &Name);
790 Value *makeIllegalNonAggregate(
Value *V,
Type *OrigType,
const Twine &Name);
804 SmallVectorImpl<VecSlice> &Slices);
806 Value *extractSlice(
Value *Vec, VecSlice S,
const Twine &Name);
807 Value *insertSlice(
Value *Whole,
Value *Part, VecSlice S,
const Twine &Name);
817 Type *intrinsicTypeFor(
Type *LegalType);
819 bool visitLoadImpl(LoadInst &OrigLI,
Type *PartType,
820 SmallVectorImpl<uint32_t> &AggIdxs,
uint64_t AggByteOffset,
821 Value *&Result,
const Twine &Name);
823 std::pair<bool, bool> visitStoreImpl(StoreInst &OrigSI,
Type *PartType,
824 SmallVectorImpl<uint32_t> &AggIdxs,
828 bool visitInstruction(Instruction &
I) {
return false; }
829 bool visitLoadInst(LoadInst &LI);
830 bool visitStoreInst(StoreInst &SI);
833 bool visitIntrinsicInst(IntrinsicInst &
II);
834 bool visitAddrSpaceCastInst(AddrSpaceCastInst &ASCI);
837 LegalizeBufferContentTypesVisitor(
const DataLayout &
DL, LLVMContext &Ctx,
838 const TargetMachine *TM)
839 : IRB(Ctx, InstSimplifyFolder(
DL)),
DL(
DL), TM(TM) {}
844Type *LegalizeBufferContentTypesVisitor::scalarArrayTypeAsVector(
Type *
T) {
848 Type *ET = AT->getElementType();
851 "should have recursed");
852 if (!
DL.typeSizeEqualsStoreSize(AT))
854 "loading padded arrays from buffer fat pinters should have recursed");
858Value *LegalizeBufferContentTypesVisitor::arrayToVector(
Value *V,
863 unsigned EC = VT->getNumElements();
864 for (
auto I : iota_range<unsigned>(0, EC,
false)) {
865 Value *Elem = IRB.CreateExtractValue(V,
I, Name +
".elem." + Twine(
I));
866 VectorRes = IRB.CreateInsertElement(VectorRes, Elem,
I,
867 Name +
".as.vec." + Twine(
I));
872Value *LegalizeBufferContentTypesVisitor::vectorToArray(
Value *V,
877 unsigned EC = AT->getNumElements();
878 for (
auto I : iota_range<unsigned>(0, EC,
false)) {
879 Value *Elem = IRB.CreateExtractElement(V,
I, Name +
".elem." + Twine(
I));
880 ArrayRes = IRB.CreateInsertValue(ArrayRes, Elem,
I,
881 Name +
".as.array." + Twine(
I));
886LegalizeBufferContentTypesVisitor::OobProperties
887LegalizeBufferContentTypesVisitor::analyzeOobProperties(
Value *Ptr,
Type *Ty,
889 OobProperties
Result(
false,
false);
892 return OobProperties(
true,
true);
898 const SCEV *PtrOp = SE->
getSCEV(Ptr);
904 Value *PtrBaseVal = PtrBase->getValue();
911 auto NumRecordsIfKnown = ZeroBasePointerToNumRecords.
find(PtrBaseVal);
912 if (NumRecordsIfKnown == ZeroBasePointerToNumRecords.
end())
915 unsigned TypeSize =
DL.getTypeStoreSize(Ty).getKnownMinValue();
920 Result.NoWrapFromMax =
true;
924 if (!NumRecordsIfKnown->second)
926 const SCEV *NumRecords = SE->
getSCEV(NumRecordsIfKnown->second);
929 std::optional<unsigned> MaybeNumRecordsWidth =
931 if (!MaybeNumRecordsWidth)
933 unsigned NumRecordsWidth = *MaybeNumRecordsWidth;
934 Type *NumRecordsTy = IRB.getIntNTy(NumRecordsWidth);
936 Type *CompareTy = IRB.getInt64Ty();
944 Result.NoPartialOOB =
true;
946 const SCEV *BoundsDiff =
951 Result.NoPartialOOB =
true;
956LegalizeBufferContentTypesVisitor::maxIntrinsicWidth(
Type *
T, Align
A,
957 OobProperties OobProps) {
963 TypeSize ElemBits =
DL.getTypeSizeInBits(VT->getElementType());
970 if (!OobProps.NoWrapFromMax)
989 if (!OobProps.NoPartialOOB)
994 return Result.value() * 8;
997Type *LegalizeBufferContentTypesVisitor::legalNonAggregateForMemOp(
999 TypeSize
Size =
DL.getTypeStoreSizeInBits(
T);
1001 if (!
DL.typeSizeEqualsStoreSize(
T))
1002 T = IRB.getIntNTy(
Size.getFixedValue());
1009 unsigned ElemSize =
DL.getTypeSizeInBits(ElemTy).getFixedValue();
1010 if (
isPowerOf2_32(ElemSize) && ElemSize >= 16 && ElemSize <= MaxWidth) {
1016 Type *BestVectorElemType =
nullptr;
1017 if (
Size.isKnownMultipleOf(32) && MaxWidth >= 32)
1018 BestVectorElemType = IRB.getInt32Ty();
1019 else if (
Size.isKnownMultipleOf(16) && MaxWidth >= 16)
1020 BestVectorElemType = IRB.getInt16Ty();
1022 BestVectorElemType = IRB.getInt8Ty();
1023 unsigned NumCastElems =
1025 if (NumCastElems == 1)
1026 return BestVectorElemType;
1030Value *LegalizeBufferContentTypesVisitor::makeLegalNonAggregate(
1031 Value *V,
Type *TargetType,
const Twine &Name) {
1032 Type *SourceType =
V->getType();
1033 TypeSize SourceSize =
DL.getTypeSizeInBits(SourceType);
1034 TypeSize TargetSize =
DL.getTypeSizeInBits(TargetType);
1035 if (SourceSize != TargetSize) {
1038 Value *AsScalar = IRB.CreateBitCast(V, ShortScalarTy, Name +
".as.scalar");
1039 Value *Zext = IRB.CreateZExt(AsScalar, ByteScalarTy, Name +
".zext");
1041 SourceType = ByteScalarTy;
1043 return IRB.CreateBitCast(V, TargetType, Name +
".legal");
1046Value *LegalizeBufferContentTypesVisitor::makeIllegalNonAggregate(
1047 Value *V,
Type *OrigType,
const Twine &Name) {
1048 Type *LegalType =
V->getType();
1049 TypeSize LegalSize =
DL.getTypeSizeInBits(LegalType);
1050 TypeSize OrigSize =
DL.getTypeSizeInBits(OrigType);
1051 if (LegalSize != OrigSize) {
1054 Value *AsScalar = IRB.CreateBitCast(V, ByteScalarTy, Name +
".bytes.cast");
1055 Value *Trunc = IRB.CreateTrunc(AsScalar, ShortScalarTy, Name +
".trunc");
1056 return IRB.CreateBitCast(Trunc, OrigType, Name +
".orig");
1058 return IRB.CreateBitCast(V, OrigType, Name +
".real.ty");
1061Type *LegalizeBufferContentTypesVisitor::intrinsicTypeFor(
Type *LegalType) {
1065 Type *ET = VT->getElementType();
1068 if (VT->getNumElements() == 1)
1070 if (
DL.getTypeSizeInBits(LegalType) == 96 &&
DL.getTypeSizeInBits(ET) < 32)
1073 switch (VT->getNumElements()) {
1077 return IRB.getInt8Ty();
1079 return IRB.getInt16Ty();
1081 return IRB.getInt32Ty();
1091void LegalizeBufferContentTypesVisitor::getVecSlices(
1092 Type *
T,
uint64_t MaxWidth, SmallVectorImpl<VecSlice> &Slices) {
1099 DL.getTypeSizeInBits(VT->getElementType()).getFixedValue();
1101 uint64_t ElemsPer4Words = 128 / ElemBitWidth;
1102 uint64_t ElemsPer2Words = ElemsPer4Words / 2;
1103 uint64_t ElemsPerWord = ElemsPer2Words / 2;
1104 uint64_t ElemsPerShort = ElemsPerWord / 2;
1105 uint64_t ElemsPerByte = ElemsPerShort / 2;
1109 uint64_t ElemsPer3Words = ElemsPerWord * 3;
1111 uint64_t TotalElems = VT->getNumElements();
1113 auto TrySlice = [&](
unsigned MaybeLen,
unsigned Width) {
1114 if (MaybeLen > 0 && Width <= MaxWidth && Index + MaybeLen <= TotalElems) {
1115 VecSlice Slice{
Index, MaybeLen};
1122 while (Index < TotalElems) {
1123 TrySlice(ElemsPer4Words, 128) || TrySlice(ElemsPer3Words, 96) ||
1124 TrySlice(ElemsPer2Words, 64) || TrySlice(ElemsPerWord, 32) ||
1125 TrySlice(ElemsPerShort, 16) || TrySlice(ElemsPerByte, 8);
1129Value *LegalizeBufferContentTypesVisitor::extractSlice(
Value *Vec, VecSlice S,
1130 const Twine &Name) {
1134 if (S.Length == VecVT->getNumElements() && S.Index == 0)
1137 return IRB.CreateExtractElement(Vec, S.Index,
1138 Name +
".slice." + Twine(S.Index));
1140 llvm::iota_range<int>(S.Index, S.Index + S.Length,
false));
1141 return IRB.CreateShuffleVector(Vec, Mask, Name +
".slice." + Twine(S.Index));
1144Value *LegalizeBufferContentTypesVisitor::insertSlice(
Value *Whole,
Value *Part,
1146 const Twine &Name) {
1150 if (S.Length == WholeVT->getNumElements() && S.Index == 0)
1152 if (S.Length == 1) {
1153 return IRB.CreateInsertElement(Whole, Part, S.Index,
1154 Name +
".slice." + Twine(S.Index));
1159 SmallVector<int> ExtPartMask(NumElems, -1);
1164 Value *ExtPart = IRB.CreateShuffleVector(Part, ExtPartMask,
1165 Name +
".ext." + Twine(S.Index));
1167 SmallVector<int>
Mask =
1172 return IRB.CreateShuffleVector(Whole, ExtPart, Mask,
1173 Name +
".parts." + Twine(S.Index));
1176bool LegalizeBufferContentTypesVisitor::visitLoadImpl(
1177 LoadInst &OrigLI,
Type *PartType, SmallVectorImpl<uint32_t> &AggIdxs,
1180 const StructLayout *Layout =
DL.getStructLayout(ST);
1182 for (
auto [
I, ElemTy,
Offset] :
1185 Changed |= visitLoadImpl(OrigLI, ElemTy, AggIdxs,
1186 AggByteOff +
Offset.getFixedValue(), Result,
1187 Name +
"." + Twine(
I));
1193 Type *ElemTy = AT->getElementType();
1196 TypeSize ElemAllocSize =
DL.getTypeAllocSize(ElemTy);
1198 for (
auto I : llvm::iota_range<uint32_t>(0, AT->getNumElements(),
1201 Changed |= visitLoadImpl(OrigLI, ElemTy, AggIdxs,
1203 Result, Name + Twine(
I));
1213 Type *ArrayAsVecType = scalarArrayTypeAsVector(PartType);
1214 OobProperties OobProps =
1216 uint64_t MaxWidth = maxIntrinsicWidth(ArrayAsVecType, PartAlign, OobProps);
1217 Type *LegalType = legalNonAggregateForMemOp(ArrayAsVecType, MaxWidth);
1220 getVecSlices(LegalType, MaxWidth, Slices);
1221 bool HasSlices = Slices.
size() > 1;
1222 bool IsAggPart = !AggIdxs.
empty();
1224 if (!HasSlices && !IsAggPart) {
1225 Type *LoadableType = intrinsicTypeFor(LegalType);
1226 if (LoadableType == PartType)
1229 IRB.SetInsertPoint(&OrigLI);
1231 NLI->mutateType(LoadableType);
1232 NLI = IRB.Insert(NLI);
1233 NLI->setName(Name +
".loadable");
1235 LoadsRes = IRB.CreateBitCast(NLI, LegalType, Name +
".from.loadable");
1237 IRB.SetInsertPoint(&OrigLI);
1245 unsigned ElemBytes =
DL.getTypeStoreSize(ElemType);
1247 if (IsAggPart && Slices.
empty())
1249 for (VecSlice S : Slices) {
1252 int64_t ByteOffset = AggByteOff + S.Index * ElemBytes;
1254 Value *NewPtr = IRB.CreateGEP(
1256 OrigPtr->
getName() +
".off.ptr." + Twine(ByteOffset),
1259 Type *LoadableType = intrinsicTypeFor(SliceType);
1260 LoadInst *NewLI = IRB.CreateAlignedLoad(
1262 Name +
".off." + Twine(ByteOffset));
1268 Value *
Loaded = IRB.CreateBitCast(NewLI, SliceType,
1269 NewLI->
getName() +
".from.loadable");
1270 LoadsRes = insertSlice(LoadsRes, Loaded, S, Name);
1273 if (LegalType != ArrayAsVecType)
1274 LoadsRes = makeIllegalNonAggregate(LoadsRes, ArrayAsVecType, Name);
1275 if (ArrayAsVecType != PartType)
1276 LoadsRes = vectorToArray(LoadsRes, PartType, Name);
1279 Result = IRB.CreateInsertValue(Result, LoadsRes, AggIdxs, Name);
1285bool LegalizeBufferContentTypesVisitor::visitLoadInst(LoadInst &LI) {
1289 SmallVector<uint32_t> AggIdxs;
1292 bool Changed = visitLoadImpl(LI, OrigType, AggIdxs, 0, Result, LI.
getName());
1301std::pair<bool, bool> LegalizeBufferContentTypesVisitor::visitStoreImpl(
1302 StoreInst &OrigSI,
Type *PartType, SmallVectorImpl<uint32_t> &AggIdxs,
1303 uint64_t AggByteOff,
const Twine &Name) {
1305 const StructLayout *Layout =
DL.getStructLayout(ST);
1307 for (
auto [
I, ElemTy,
Offset] :
1310 Changed |= std::get<0>(visitStoreImpl(OrigSI, ElemTy, AggIdxs,
1311 AggByteOff +
Offset.getFixedValue(),
1312 Name +
"." + Twine(
I)));
1315 return std::make_pair(
Changed,
false);
1318 Type *ElemTy = AT->getElementType();
1321 TypeSize ElemAllocSize =
DL.getTypeAllocSize(ElemTy);
1323 for (
auto I : llvm::iota_range<uint32_t>(0, AT->getNumElements(),
1326 Changed |= std::get<0>(visitStoreImpl(
1327 OrigSI, ElemTy, AggIdxs,
1331 return std::make_pair(
Changed,
false);
1336 Value *NewData = OrigData;
1338 bool IsAggPart = !AggIdxs.
empty();
1340 NewData = IRB.CreateExtractValue(NewData, AggIdxs, Name);
1342 Type *ArrayAsVecType = scalarArrayTypeAsVector(PartType);
1343 if (ArrayAsVecType != PartType) {
1344 NewData = arrayToVector(NewData, ArrayAsVecType, Name);
1348 OobProperties OobProps =
1350 uint64_t MaxWidth = maxIntrinsicWidth(ArrayAsVecType, PartAlign, OobProps);
1351 Type *LegalType = legalNonAggregateForMemOp(ArrayAsVecType, MaxWidth);
1352 if (LegalType != ArrayAsVecType) {
1353 NewData = makeLegalNonAggregate(NewData, LegalType, Name);
1357 getVecSlices(LegalType, MaxWidth, Slices);
1358 bool NeedToSplit = Slices.
size() > 1 || IsAggPart;
1360 Type *StorableType = intrinsicTypeFor(LegalType);
1361 if (StorableType == PartType)
1362 return std::make_pair(
false,
false);
1363 NewData = IRB.CreateBitCast(NewData, StorableType, Name +
".storable");
1365 return std::make_pair(
true,
true);
1370 if (IsAggPart && Slices.
empty())
1372 unsigned ElemBytes =
DL.getTypeStoreSize(ElemType);
1374 for (VecSlice S : Slices) {
1377 int64_t ByteOffset = AggByteOff + S.Index * ElemBytes;
1378 Value *NewPtr = IRB.CreateGEP(
1379 IRB.getInt8Ty(), OrigPtr, IRB.getInt32(ByteOffset),
1380 OrigPtr->
getName() +
".part." + Twine(S.Index),
1383 Value *DataSlice = extractSlice(NewData, S, Name);
1384 Type *StorableType = intrinsicTypeFor(SliceType);
1385 DataSlice = IRB.CreateBitCast(DataSlice, StorableType,
1386 DataSlice->
getName() +
".storable");
1390 NewSI->setOperand(0, DataSlice);
1391 NewSI->setOperand(1, NewPtr);
1394 return std::make_pair(
true,
false);
1397bool LegalizeBufferContentTypesVisitor::visitStoreInst(StoreInst &SI) {
1400 IRB.SetInsertPoint(&SI);
1401 SmallVector<uint32_t> AggIdxs;
1402 Value *OrigData =
SI.getValueOperand();
1403 auto [
Changed, ModifiedInPlace] =
1404 visitStoreImpl(SI, OrigData->
getType(), AggIdxs, 0, OrigData->
getName());
1405 if (
Changed && !ModifiedInPlace)
1406 SI.eraseFromParent();
1410bool LegalizeBufferContentTypesVisitor::visitAddrSpaceCastInst(
1411 AddrSpaceCastInst &AI) {
1416 auto Record = ZeroBasePointerToNumRecords.
find(Src);
1417 if (Record != ZeroBasePointerToNumRecords.
end())
1418 ZeroBasePointerToNumRecords.
insert({&AI,
Record->second});
1420 ZeroBasePointerToNumRecords.
insert({&AI,
nullptr});
1424bool LegalizeBufferContentTypesVisitor::visitIntrinsicInst(IntrinsicInst &
II) {
1425 if (
II.getIntrinsicID() != Intrinsic::amdgcn_make_buffer_rsrc)
1427 ZeroBasePointerToNumRecords.
insert({&
II,
II.getOperand(2)});
1431bool LegalizeBufferContentTypesVisitor::processFunction(
Function &
F,
1432 ScalarEvolution *SE) {
1439 ZeroBasePointerToNumRecords.
clear();
1446static std::pair<Constant *, Constant *>
1449 return std::make_pair(
C->getAggregateElement(0u),
C->getAggregateElement(1u));
1454class FatPtrConstMaterializer final :
public ValueMaterializer {
1455 BufferFatPtrToStructTypeMap *TypeMap;
1461 ValueMapper InternalMapper;
1463 Constant *materializeBufferFatPtrConst(Constant *
C);
1467 FatPtrConstMaterializer(BufferFatPtrToStructTypeMap *TypeMap,
1470 InternalMapper(UnderlyingMap,
RF_None, TypeMap, this) {}
1471 ~FatPtrConstMaterializer() =
default;
1477Constant *FatPtrConstMaterializer::materializeBufferFatPtrConst(Constant *
C) {
1478 Type *SrcTy =
C->getType();
1480 if (
C->isNullValue())
1481 return ConstantAggregateZero::getNullValue(NewTy);
1494 if (Constant *S =
VC->getSplatValue()) {
1499 auto EC =
VC->getType()->getElementCount();
1505 for (
Value *
Op :
VC->operand_values()) {
1520 "fat pointer) values are not supported");
1524 "constant exprs containing ptr addrspace(7) (buffer "
1525 "fat pointer) values should have been expanded earlier");
1530Value *FatPtrConstMaterializer::materialize(
Value *V) {
1538 return materializeBufferFatPtrConst(
C);
1546class SplitPtrStructs :
public InstVisitor<SplitPtrStructs, PtrParts> {
1589 void processConditionals();
1639void SplitPtrStructs::copyMetadata(
Value *Dest,
Value *Src) {
1643 if (!DestI || !SrcI)
1646 DestI->copyMetadata(*SrcI);
1651 "of something that wasn't rewritten");
1652 auto *RsrcEntry = &RsrcParts[
V];
1653 auto *OffEntry = &OffParts[
V];
1654 if (*RsrcEntry && *OffEntry)
1655 return {*RsrcEntry, *OffEntry};
1659 return {*RsrcEntry = Rsrc, *OffEntry =
Off};
1662 IRBuilder<InstSimplifyFolder>::InsertPointGuard Guard(IRB);
1667 return {*RsrcEntry = Rsrc, *OffEntry =
Off};
1670 IRB.SetInsertPoint(*
I->getInsertionPointAfterDef());
1671 IRB.SetCurrentDebugLocation(
I->getDebugLoc());
1673 IRB.SetInsertPointPastAllocas(
A->getParent());
1674 IRB.SetCurrentDebugLocation(
DebugLoc());
1676 Value *Rsrc = IRB.CreateExtractValue(V, 0,
V->getName() +
".rsrc");
1677 Value *
Off = IRB.CreateExtractValue(V, 1,
V->getName() +
".off");
1678 return {*RsrcEntry = Rsrc, *OffEntry =
Off};
1691 V =
GEP->getPointerOperand();
1693 V = ASC->getPointerOperand();
1697void SplitPtrStructs::getPossibleRsrcRoots(Instruction *
I,
1698 SmallPtrSetImpl<Value *> &Roots,
1699 SmallPtrSetImpl<Value *> &Seen) {
1703 for (
Value *In :
PHI->incoming_values()) {
1710 if (!Seen.
insert(SI).second)
1725void SplitPtrStructs::processConditionals() {
1726 SmallDenseMap<Value *, Value *> FoundRsrcs;
1727 SmallPtrSet<Value *, 4> Roots;
1728 SmallPtrSet<Value *, 4> Seen;
1729 for (Instruction *
I : Conditionals) {
1731 Value *Rsrc = RsrcParts[
I];
1733 assert(Rsrc && Off &&
"must have visited conditionals by now");
1735 std::optional<Value *> MaybeRsrc;
1736 auto MaybeFoundRsrc = FoundRsrcs.
find(
I);
1737 if (MaybeFoundRsrc != FoundRsrcs.
end()) {
1738 MaybeRsrc = MaybeFoundRsrc->second;
1740 IRBuilder<InstSimplifyFolder>::InsertPointGuard Guard(IRB);
1743 getPossibleRsrcRoots(
I, Roots, Seen);
1746 for (
Value *V : Roots)
1748 for (
Value *V : Seen)
1760 if (Diff.size() == 1) {
1761 Value *RootVal = *Diff.begin();
1765 MaybeRsrc = std::get<0>(getPtrParts(RootVal));
1767 MaybeRsrc = RootVal;
1775 IRB.SetInsertPoint(*
PHI->getInsertionPointAfterDef());
1776 IRB.SetCurrentDebugLocation(
PHI->getDebugLoc());
1778 NewRsrc = *MaybeRsrc;
1781 auto *RsrcPHI = IRB.CreatePHI(RsrcTy,
PHI->getNumIncomingValues());
1782 RsrcPHI->takeName(Rsrc);
1783 for (
auto [V, BB] :
llvm::zip(
PHI->incoming_values(),
PHI->blocks())) {
1784 Value *VRsrc = std::get<0>(getPtrParts(V));
1785 RsrcPHI->addIncoming(VRsrc, BB);
1787 copyMetadata(RsrcPHI,
PHI);
1792 auto *NewOff = IRB.CreatePHI(OffTy,
PHI->getNumIncomingValues());
1793 NewOff->takeName(Off);
1794 for (
auto [V, BB] :
llvm::zip(
PHI->incoming_values(),
PHI->blocks())) {
1795 assert(OffParts.
count(V) &&
"An offset part had to be created by now");
1796 Value *VOff = std::get<1>(getPtrParts(V));
1797 NewOff->addIncoming(VOff, BB);
1799 copyMetadata(NewOff,
PHI);
1809 RsrcInst->replaceAllUsesWith(NewRsrc);
1813 OffInst->replaceAllUsesWith(NewOff);
1818 for (
Value *V : Seen)
1819 FoundRsrcs[
V] = NewRsrc;
1824 if (RsrcInst != *MaybeRsrc) {
1826 RsrcInst->replaceAllUsesWith(*MaybeRsrc);
1829 for (
Value *V : Seen)
1830 FoundRsrcs[
V] = *MaybeRsrc;
1838void SplitPtrStructs::killAndReplaceSplitInstructions(
1839 SmallVectorImpl<Instruction *> &Origs) {
1840 for (Instruction *
I : ConditionalTemps)
1841 I->eraseFromParent();
1843 for (Instruction *
I : Origs) {
1849 for (DbgVariableRecord *Dbg : Dbgs) {
1850 auto &
DL =
I->getDataLayout();
1852 "We should've RAUW'd away loads, stores, etc. at this point");
1853 DbgVariableRecord *OffDbg =
Dbg->clone();
1854 auto [Rsrc,
Off] = getPtrParts(
I);
1856 int64_t RsrcSz =
DL.getTypeSizeInBits(Rsrc->
getType());
1857 int64_t OffSz =
DL.getTypeSizeInBits(
Off->getType());
1859 std::optional<DIExpression *> RsrcExpr =
1862 std::optional<DIExpression *> OffExpr =
1873 Dbg->setExpression(*RsrcExpr);
1874 Dbg->replaceVariableLocationOp(
I, Rsrc);
1881 I->replaceUsesWithIf(
Poison, [&](
const Use &U) ->
bool {
1887 if (
I->use_empty()) {
1888 I->eraseFromParent();
1891 IRB.SetInsertPoint(*
I->getInsertionPointAfterDef());
1892 IRB.SetCurrentDebugLocation(
I->getDebugLoc());
1893 auto [Rsrc,
Off] = getPtrParts(
I);
1895 Struct = IRB.CreateInsertValue(Struct, Rsrc, 0);
1896 Struct = IRB.CreateInsertValue(Struct, Off, 1);
1897 copyMetadata(Struct,
I);
1899 I->replaceAllUsesWith(Struct);
1900 I->eraseFromParent();
1904void SplitPtrStructs::setAlign(CallInst *Intr, Align
A,
unsigned RsrcArgIdx) {
1906 Intr->
addParamAttr(RsrcArgIdx, Attribute::getWithAlignment(Ctx,
A));
1912 case AtomicOrdering::Release:
1913 case AtomicOrdering::AcquireRelease:
1914 case AtomicOrdering::SequentiallyConsistent:
1915 IRB.CreateFence(AtomicOrdering::Release, SSID);
1925 case AtomicOrdering::Acquire:
1926 case AtomicOrdering::AcquireRelease:
1927 case AtomicOrdering::SequentiallyConsistent:
1928 IRB.CreateFence(AtomicOrdering::Acquire, SSID);
1935Value *SplitPtrStructs::handleMemoryInst(Instruction *
I,
Value *Arg,
Value *Ptr,
1936 Type *Ty, Align Alignment,
1939 IRB.SetInsertPoint(
I);
1941 auto [Rsrc,
Off] = getPtrParts(Ptr);
1944 Args.push_back(Arg);
1945 Args.push_back(Rsrc);
1946 Args.push_back(Off);
1947 insertPreMemOpFence(Order, SSID);
1951 Args.push_back(IRB.getInt32(0));
1956 Args.push_back(IRB.getInt32(Aux));
1960 IID = Order == AtomicOrdering::NotAtomic
1961 ? Intrinsic::amdgcn_raw_ptr_buffer_load
1962 : Intrinsic::amdgcn_raw_ptr_atomic_buffer_load;
1964 IID = Intrinsic::amdgcn_raw_ptr_buffer_store;
1966 switch (RMW->getOperation()) {
1968 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_swap;
1971 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_add;
1974 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_sub;
1977 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_and;
1980 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_or;
1983 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_xor;
1986 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_smax;
1989 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_smin;
1992 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_umax;
1995 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_umin;
1998 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_fadd;
2001 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_fmax;
2004 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_fmin;
2007 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_cond_sub_u32;
2010 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_sub_clamp_u32;
2014 "atomic floating point subtraction not supported for "
2015 "buffer resources and should've been expanded away");
2020 "atomic floating point fmaximum not supported for "
2021 "buffer resources and should've been expanded away");
2026 "atomic floating point fminimum not supported for "
2027 "buffer resources and should've been expanded away");
2032 "atomic floating point fmaximumnum not supported for "
2033 "buffer resources and should've been expanded away");
2038 "atomic floating point fminimumnum not supported for "
2039 "buffer resources and should've been expanded away");
2044 "atomic nand not supported for buffer resources and "
2045 "should've been expanded away");
2050 "wrapping increment/decrement not supported for "
2051 "buffer resources and should've been expanded away");
2058 CallInst *
Call = IRB.CreateIntrinsicWithoutFolding(IID, Ty, Args);
2059 copyMetadata(
Call,
I);
2060 setAlign(
Call, Alignment, Arg ? 1 : 0);
2063 insertPostMemOpFence(Order, SSID);
2067 I->replaceAllUsesWith(
Call);
2071PtrParts SplitPtrStructs::visitInstruction(Instruction &
I) {
2072 return {
nullptr,
nullptr};
2075PtrParts SplitPtrStructs::visitLoadInst(LoadInst &LI) {
2077 return {
nullptr,
nullptr};
2081 return {
nullptr,
nullptr};
2084PtrParts SplitPtrStructs::visitStoreInst(StoreInst &SI) {
2086 return {
nullptr,
nullptr};
2087 Value *Arg =
SI.getValueOperand();
2088 handleMemoryInst(&SI, Arg,
SI.getPointerOperand(), Arg->
getType(),
2089 SI.getAlign(),
SI.getOrdering(),
SI.isVolatile(),
2090 SI.getSyncScopeID());
2091 return {
nullptr,
nullptr};
2094PtrParts SplitPtrStructs::visitAtomicRMWInst(AtomicRMWInst &AI) {
2096 return {
nullptr,
nullptr};
2101 return {
nullptr,
nullptr};
2106PtrParts SplitPtrStructs::visitAtomicCmpXchgInst(AtomicCmpXchgInst &AI) {
2109 return {
nullptr,
nullptr};
2110 IRB.SetInsertPoint(&AI);
2115 bool IsNonTemporal = AI.
getMetadata(LLVMContext::MD_nontemporal);
2117 auto [Rsrc,
Off] = getPtrParts(Ptr);
2118 insertPreMemOpFence(Order, SSID);
2125 CallInst *
Call = IRB.CreateIntrinsicWithoutFolding(
2126 Intrinsic::amdgcn_raw_ptr_buffer_atomic_cmpswap, Ty,
2128 IRB.getInt32(0), IRB.getInt32(Aux)});
2129 copyMetadata(
Call, &AI);
2132 insertPostMemOpFence(Order, SSID);
2135 Res = IRB.CreateInsertValue(Res,
Call, 0);
2137 Res = IRB.CreateInsertValue(Res, Succeeded, 1);
2140 return {
nullptr,
nullptr};
2143PtrParts SplitPtrStructs::visitGetElementPtrInst(GetElementPtrInst &
GEP) {
2144 using namespace llvm::PatternMatch;
2145 Value *Ptr =
GEP.getPointerOperand();
2147 return {
nullptr,
nullptr};
2148 IRB.SetInsertPoint(&
GEP);
2150 auto [Rsrc,
Off] = getPtrParts(Ptr);
2151 const DataLayout &
DL =
GEP.getDataLayout();
2152 bool IsNUW =
GEP.hasNoUnsignedWrap();
2153 bool IsNUSW =
GEP.hasNoUnsignedSignedWrap();
2164 GEP.mutateType(FatPtrTy);
2166 GEP.mutateType(ResTy);
2168 if (BroadcastsPtr) {
2169 Rsrc = IRB.CreateVectorSplat(ResRsrcVecTy->getElementCount(), Rsrc,
2171 Off = IRB.CreateVectorSplat(ResRsrcVecTy->getElementCount(), Off,
2179 bool HasNonNegativeOff =
false;
2181 HasNonNegativeOff = !CI->isNegative();
2187 NewOff = IRB.CreateAdd(Off, OffAccum,
"",
2188 IsNUW || (IsNUSW && HasNonNegativeOff),
2191 copyMetadata(NewOff, &
GEP);
2194 return {Rsrc, NewOff};
2197PtrParts SplitPtrStructs::visitPtrToIntInst(PtrToIntInst &PI) {
2200 return {
nullptr,
nullptr};
2201 IRB.SetInsertPoint(&PI);
2206 auto [Rsrc,
Off] = getPtrParts(Ptr);
2212 Res = IRB.CreateIntCast(Off, ResTy,
false,
2215 Value *RsrcInt = IRB.CreatePtrToInt(Rsrc, ResTy, PI.
getName() +
".rsrc");
2216 Value *Shl = IRB.CreateShl(
2219 "", Width >= FatPtrWidth, Width > FatPtrWidth);
2220 Value *OffCast = IRB.CreateIntCast(Off, ResTy,
false,
2222 Res = IRB.CreateOr(Shl, OffCast);
2225 copyMetadata(Res, &PI);
2229 return {
nullptr,
nullptr};
2232PtrParts SplitPtrStructs::visitPtrToAddrInst(PtrToAddrInst &PA) {
2235 return {
nullptr,
nullptr};
2236 IRB.SetInsertPoint(&PA);
2238 auto [Rsrc,
Off] = getPtrParts(Ptr);
2239 Value *Res = IRB.CreateIntCast(Off, PA.
getType(),
false);
2240 copyMetadata(Res, &PA);
2244 return {
nullptr,
nullptr};
2247PtrParts SplitPtrStructs::visitIntToPtrInst(IntToPtrInst &IP) {
2249 return {
nullptr,
nullptr};
2250 IRB.SetInsertPoint(&IP);
2259 Type *RsrcTy = RetTy->getElementType(0);
2260 Type *OffTy = RetTy->getElementType(1);
2269 RsrcInt = IRB.CreateIntCast(RsrcPart, RsrcIntTy,
false);
2271 Value *Rsrc = IRB.CreateIntToPtr(RsrcInt, RsrcTy, IP.
getName() +
".rsrc");
2273 IRB.CreateIntCast(
Int, OffTy,
false, IP.
getName() +
".off");
2275 copyMetadata(Rsrc, &IP);
2280PtrParts SplitPtrStructs::visitAddrSpaceCastInst(AddrSpaceCastInst &
I) {
2284 return {
nullptr,
nullptr};
2285 IRB.SetInsertPoint(&
I);
2288 if (
In->getType() ==
I.getType()) {
2289 auto [Rsrc,
Off] = getPtrParts(In);
2295 Type *RsrcTy = ResTy->getElementType(0);
2296 Type *OffTy = ResTy->getElementType(1);
2302 if (InConst && InConst->isNullValue()) {
2305 return {NullRsrc, ZeroOff};
2311 return {PoisonRsrc, PoisonOff};
2317 return {UndefRsrc, UndefOff};
2322 "only buffer resources (addrspace 8) and null/poison pointers can be "
2323 "cast to buffer fat pointers (addrspace 7)");
2325 return {
In, ZeroOff};
2328PtrParts SplitPtrStructs::visitICmpInst(ICmpInst &Cmp) {
2331 return {
nullptr,
nullptr};
2333 IRB.SetInsertPoint(&Cmp);
2334 ICmpInst::Predicate Pred =
Cmp.getPredicate();
2336 assert((Pred == ICmpInst::ICMP_EQ || Pred == ICmpInst::ICMP_NE) &&
2337 "Pointer comparison is only equal or unequal");
2338 auto [LhsRsrc, LhsOff] = getPtrParts(Lhs);
2339 auto [RhsRsrc, RhsOff] = getPtrParts(Rhs);
2340 Value *Res = IRB.CreateICmp(Pred, LhsOff, RhsOff);
2341 copyMetadata(Res, &Cmp);
2344 Cmp.replaceAllUsesWith(Res);
2345 return {
nullptr,
nullptr};
2348PtrParts SplitPtrStructs::visitFreezeInst(FreezeInst &
I) {
2350 return {
nullptr,
nullptr};
2351 IRB.SetInsertPoint(&
I);
2352 auto [Rsrc,
Off] = getPtrParts(
I.getOperand(0));
2354 Value *RsrcRes = IRB.CreateFreeze(Rsrc,
I.getName() +
".rsrc");
2355 copyMetadata(RsrcRes, &
I);
2356 Value *OffRes = IRB.CreateFreeze(Off,
I.getName() +
".off");
2357 copyMetadata(OffRes, &
I);
2359 return {RsrcRes, OffRes};
2362PtrParts SplitPtrStructs::visitExtractElementInst(ExtractElementInst &
I) {
2364 return {
nullptr,
nullptr};
2365 IRB.SetInsertPoint(&
I);
2366 Value *Vec =
I.getVectorOperand();
2367 Value *Idx =
I.getIndexOperand();
2368 auto [Rsrc,
Off] = getPtrParts(Vec);
2370 Value *RsrcRes = IRB.CreateExtractElement(Rsrc, Idx,
I.getName() +
".rsrc");
2371 copyMetadata(RsrcRes, &
I);
2372 Value *OffRes = IRB.CreateExtractElement(Off, Idx,
I.getName() +
".off");
2373 copyMetadata(OffRes, &
I);
2375 return {RsrcRes, OffRes};
2378PtrParts SplitPtrStructs::visitInsertElementInst(InsertElementInst &
I) {
2382 return {
nullptr,
nullptr};
2383 IRB.SetInsertPoint(&
I);
2384 Value *Vec =
I.getOperand(0);
2385 Value *Elem =
I.getOperand(1);
2386 Value *Idx =
I.getOperand(2);
2387 auto [VecRsrc, VecOff] = getPtrParts(Vec);
2388 auto [ElemRsrc, ElemOff] = getPtrParts(Elem);
2391 IRB.CreateInsertElement(VecRsrc, ElemRsrc, Idx,
I.getName() +
".rsrc");
2392 copyMetadata(RsrcRes, &
I);
2394 IRB.CreateInsertElement(VecOff, ElemOff, Idx,
I.getName() +
".off");
2395 copyMetadata(OffRes, &
I);
2397 return {RsrcRes, OffRes};
2400PtrParts SplitPtrStructs::visitShuffleVectorInst(ShuffleVectorInst &
I) {
2403 return {
nullptr,
nullptr};
2404 IRB.SetInsertPoint(&
I);
2407 Value *V2 =
I.getOperand(1);
2408 ArrayRef<int>
Mask =
I.getShuffleMask();
2409 auto [V1Rsrc, V1Off] = getPtrParts(
V1);
2410 auto [V2Rsrc, V2Off] = getPtrParts(V2);
2413 IRB.CreateShuffleVector(V1Rsrc, V2Rsrc, Mask,
I.getName() +
".rsrc");
2414 copyMetadata(RsrcRes, &
I);
2416 IRB.CreateShuffleVector(V1Off, V2Off, Mask,
I.getName() +
".off");
2417 copyMetadata(OffRes, &
I);
2419 return {RsrcRes, OffRes};
2422PtrParts SplitPtrStructs::visitPHINode(PHINode &
PHI) {
2424 return {
nullptr,
nullptr};
2425 IRB.SetInsertPoint(*
PHI.getInsertionPointAfterDef());
2431 Value *TmpRsrc = IRB.CreateExtractValue(&
PHI, 0,
PHI.getName() +
".rsrc");
2432 Value *TmpOff = IRB.CreateExtractValue(&
PHI, 1,
PHI.getName() +
".off");
2433 Conditionals.push_back(&
PHI);
2435 return {TmpRsrc, TmpOff};
2438PtrParts SplitPtrStructs::visitSelectInst(SelectInst &SI) {
2440 return {
nullptr,
nullptr};
2441 IRB.SetInsertPoint(&SI);
2444 Value *True =
SI.getTrueValue();
2445 Value *False =
SI.getFalseValue();
2446 auto [TrueRsrc, TrueOff] = getPtrParts(True);
2447 auto [FalseRsrc, FalseOff] = getPtrParts(False);
2450 IRB.CreateSelect(
Cond, TrueRsrc, FalseRsrc,
SI.getName() +
".rsrc", &SI);
2451 copyMetadata(RsrcRes, &SI);
2452 Conditionals.push_back(&SI);
2454 IRB.CreateSelect(
Cond, TrueOff, FalseOff,
SI.getName() +
".off", &SI);
2455 copyMetadata(OffRes, &SI);
2457 return {RsrcRes, OffRes};
2468 case Intrinsic::amdgcn_make_buffer_rsrc:
2469 case Intrinsic::ptrmask:
2470 case Intrinsic::invariant_start:
2471 case Intrinsic::invariant_end:
2472 case Intrinsic::launder_invariant_group:
2473 case Intrinsic::strip_invariant_group:
2474 case Intrinsic::memcpy:
2475 case Intrinsic::memcpy_inline:
2476 case Intrinsic::memmove:
2477 case Intrinsic::memset:
2478 case Intrinsic::memset_inline:
2479 case Intrinsic::experimental_memset_pattern:
2480 case Intrinsic::amdgcn_load_to_lds:
2481 case Intrinsic::amdgcn_load_async_to_lds:
2486PtrParts SplitPtrStructs::visitIntrinsicInst(IntrinsicInst &
I) {
2491 case Intrinsic::amdgcn_make_buffer_rsrc: {
2493 return {
nullptr,
nullptr};
2495 Value *Stride =
I.getArgOperand(1);
2496 Value *NumRecords =
I.getArgOperand(2);
2499 Type *RsrcType = SplitType->getElementType(0);
2500 Type *OffType = SplitType->getElementType(1);
2501 IRB.SetInsertPoint(&
I);
2502 Value *Rsrc = IRB.CreateIntrinsic(
2503 IID, {RsrcType,
Base->getType(), NumRecords->
getType()},
2505 copyMetadata(Rsrc, &
I);
2509 return {Rsrc,
Zero};
2511 case Intrinsic::ptrmask: {
2512 Value *Ptr =
I.getArgOperand(0);
2514 return {
nullptr,
nullptr};
2516 IRB.SetInsertPoint(&
I);
2517 auto [Rsrc,
Off] = getPtrParts(Ptr);
2518 if (
Mask->getType() !=
Off->getType())
2520 "pointer (data layout not set up correctly?)");
2521 Value *OffRes = IRB.CreateAnd(Off, Mask,
I.getName() +
".off");
2522 copyMetadata(OffRes, &
I);
2524 return {Rsrc, OffRes};
2528 case Intrinsic::invariant_start: {
2529 Value *Ptr =
I.getArgOperand(1);
2531 return {
nullptr,
nullptr};
2532 IRB.SetInsertPoint(&
I);
2533 auto [Rsrc,
Off] = getPtrParts(Ptr);
2535 auto *NewRsrc = IRB.CreateIntrinsic(IID, {NewTy}, {
I.getOperand(0), Rsrc});
2536 copyMetadata(NewRsrc, &
I);
2539 I.replaceAllUsesWith(NewRsrc);
2540 return {
nullptr,
nullptr};
2542 case Intrinsic::invariant_end: {
2543 Value *RealPtr =
I.getArgOperand(2);
2545 return {
nullptr,
nullptr};
2546 IRB.SetInsertPoint(&
I);
2547 Value *RealRsrc = getPtrParts(RealPtr).first;
2548 Value *InvPtr =
I.getArgOperand(0);
2550 Value *NewRsrc = IRB.CreateIntrinsic(IID, {RealRsrc->
getType()},
2551 {InvPtr,
Size, RealRsrc});
2552 copyMetadata(NewRsrc, &
I);
2555 I.replaceAllUsesWith(NewRsrc);
2556 return {
nullptr,
nullptr};
2558 case Intrinsic::launder_invariant_group:
2559 case Intrinsic::strip_invariant_group: {
2560 Value *Ptr =
I.getArgOperand(0);
2562 return {
nullptr,
nullptr};
2563 IRB.SetInsertPoint(&
I);
2564 auto [Rsrc,
Off] = getPtrParts(Ptr);
2565 Value *NewRsrc = IRB.CreateIntrinsic(IID, {Rsrc->
getType()}, {Rsrc});
2566 copyMetadata(NewRsrc, &
I);
2569 return {NewRsrc,
Off};
2571 case Intrinsic::amdgcn_load_to_lds:
2572 case Intrinsic::amdgcn_load_async_to_lds: {
2573 Value *Ptr =
I.getArgOperand(0);
2575 return {
nullptr,
nullptr};
2576 IRB.SetInsertPoint(&
I);
2577 auto [Rsrc,
Off] = getPtrParts(Ptr);
2578 Value *LDSPtr =
I.getArgOperand(1);
2579 Value *LoadSize =
I.getArgOperand(2);
2580 Value *ImmOff =
I.getArgOperand(3);
2581 Value *Aux =
I.getArgOperand(4);
2582 Value *SOffset = IRB.getInt32(0);
2584 IID == Intrinsic::amdgcn_load_to_lds
2585 ? Intrinsic::amdgcn_raw_ptr_buffer_load_lds
2586 : Intrinsic::amdgcn_raw_ptr_buffer_load_async_lds;
2587 Instruction *NewLoad = IRB.CreateIntrinsicWithoutFolding(
2588 NewIntr, {}, {Rsrc, LDSPtr, LoadSize,
Off, SOffset, ImmOff, Aux});
2589 copyMetadata(NewLoad, &
I);
2591 I.replaceAllUsesWith(NewLoad);
2592 return {
nullptr,
nullptr};
2595 return {
nullptr,
nullptr};
2598void SplitPtrStructs::processFunction(
Function &
F) {
2600 SmallVector<Instruction *, 0> Originals(
2602 LLVM_DEBUG(
dbgs() <<
"Splitting pointer structs in function: " <<
F.getName()
2604 for (Instruction *
I : Originals) {
2612 assert(((Rsrc && Off) || (!Rsrc && !Off)) &&
2613 "Can't have a resource but no offset");
2615 RsrcParts[
I] = Rsrc;
2619 processConditionals();
2620 killAndReplaceSplitInstructions(Originals);
2626 Conditionals.clear();
2627 ConditionalTemps.clear();
2631class AMDGPULowerBufferFatPointers :
public ModulePass {
2635 AMDGPULowerBufferFatPointers() : ModulePass(
ID) {}
2638 bool runOnModule(
Module &M)
override;
2640 void getAnalysisUsage(AnalysisUsage &AU)
const override;
2648 BufferFatPtrToStructTypeMap *TypeMap) {
2649 bool HasFatPointers =
false;
2652 HasFatPointers |= (
I.getType() != TypeMap->remapType(
I.getType()));
2654 for (
const Value *V :
I.operand_values())
2655 HasFatPointers |= (V->getType() != TypeMap->remapType(V->getType()));
2657 return HasFatPointers;
2661 BufferFatPtrToStructTypeMap *TypeMap) {
2662 Type *Ty =
F.getFunctionType();
2663 return Ty != TypeMap->remapType(Ty);
2679 while (!OldF->
empty()) {
2693 CloneMap[&NewArg] = &OldArg;
2694 NewArg.takeName(&OldArg);
2695 Type *OldArgTy = OldArg.getType(), *NewArgTy = NewArg.getType();
2697 NewArg.mutateType(OldArgTy);
2698 OldArg.replaceAllUsesWith(&NewArg);
2699 NewArg.mutateType(NewArgTy);
2703 if (OldArgTy != NewArgTy && !IsIntrinsic)
2706 AttributeFuncs::typeIncompatible(NewArgTy, ArgAttr));
2713 AttributeFuncs::typeIncompatible(NewF->
getReturnType(), RetAttrs));
2715 NewF->
getContext(), OldAttrs.getFnAttrs(), RetAttrs, ArgAttrs));
2723 CloneMap[&BB] = &BB;
2729bool AMDGPULowerBufferFatPointers::run(
Module &M,
const TargetMachine &TM,
2732 const DataLayout &
DL =
M.getDataLayout();
2738 LLVMContext &Ctx =
M.getContext();
2740 BufferFatPtrToStructTypeMap StructTM(
DL);
2741 BufferFatPtrToIntTypeMap IntTM(
DL);
2745 Ctx.
emitError(
"global variables with a buffer fat pointer address "
2746 "space (7) are not supported");
2748 GV.eraseFromParent();
2753 Type *VT = GV.getValueType();
2754 if (VT != StructTM.remapType(VT)) {
2756 Ctx.
emitError(
"global variables that contain buffer fat pointers "
2757 "(address space 7 pointers) are unsupported. Use "
2758 "buffer resource pointers (address space 8) instead");
2760 GV.eraseFromParent();
2776 SmallPtrSet<Constant *, 8> Visited;
2777 SetVector<Constant *> BufferFatPtrConsts;
2778 while (!Worklist.
empty()) {
2780 if (!Visited.
insert(
C).second)
2796 StoreFatPtrsAsIntsAndExpandMemcpyVisitor MemOpsRewrite(&IntTM,
DL,
2798 LegalizeBufferContentTypesVisitor BufferContentsTypeRewrite(
2799 DL,
M.getContext(), &TM);
2803 const TargetTransformInfo *
TTI = GetTTI(
F);
2804 ScalarEvolution *SE = GetSE(
F);
2805 Changed |= MemOpsRewrite.processFunction(
F,
TTI, SE);
2806 if (InterfaceChange || BodyChanges) {
2807 NeedsRemap.
push_back(std::make_pair(&
F, InterfaceChange));
2808 Changed |= BufferContentsTypeRewrite.processFunction(
F, SE);
2811 if (NeedsRemap.
empty())
2818 FatPtrConstMaterializer Materializer(&StructTM, CloneMap);
2820 ValueMapper LowerInFuncs(CloneMap,
RF_None, &StructTM, &Materializer);
2821 for (
auto [
F, InterfaceChange] : NeedsRemap) {
2823 if (InterfaceChange)
2829 LowerInFuncs.remapFunction(*NewF);
2834 if (InterfaceChange) {
2835 F->replaceAllUsesWith(NewF);
2836 F->eraseFromParent();
2844 SplitPtrStructs Splitter(
DL,
M.getContext(), &TM);
2846 Splitter.processFunction(*
F);
2851 F->eraseFromParent();
2855 F->replaceAllUsesWith(*NewF);
2861bool AMDGPULowerBufferFatPointers::runOnModule(
Module &M) {
2862 TargetPassConfig &TPC = getAnalysis<TargetPassConfig>();
2863 const TargetMachine &TM = TPC.
getTM<TargetMachine>();
2864 auto GetTTI = [&](
Function &
F) ->
const TargetTransformInfo * {
2865 if (
F.isDeclaration())
2867 return &getAnalysis<TargetTransformInfoWrapperPass>().getTTI(
F);
2869 auto GetSE = [&](
Function &
F) -> ScalarEvolution * {
2870 if (
F.isDeclaration())
2872 return &getAnalysis<ScalarEvolutionWrapperPass>(
F).getSE();
2874 return run(M, TM, GetTTI, GetSE);
2877char AMDGPULowerBufferFatPointers::ID = 0;
2881void AMDGPULowerBufferFatPointers::getAnalysisUsage(
AnalysisUsage &AU)
const {
2887#define PASS_DESC "Lower buffer fat pointer operations to buffer resources"
2898 return new AMDGPULowerBufferFatPointers();
2905 if (
F.isDeclaration())
2910 if (
F.isDeclaration())
2914 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.