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;
443 const TargetTransformInfo *
TTI;
455 StoreFatPtrsAsIntsAndExpandMemcpyVisitor(BufferFatPtrToIntTypeMap *TypeMap,
456 const DataLayout &
DL,
458 : TypeMap(TypeMap), IRB(Ctx, InstSimplifyFolder(
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::fatPtrsToInts(
480 if (
Find != ConvertedForStore.
end())
483 Value *Cast = IRB.CreatePtrToInt(V, To, Name +
".int");
484 ConvertedForStore[
V] = Cast;
492 Type *FromPart = AT->getArrayElementType();
494 for (uint64_t
I = 0,
E = AT->getArrayNumElements();
I <
E; ++
I) {
497 fatPtrsToInts(
Field, FromPart, ToPart, Name +
"." + Twine(
I));
498 Ret = IRB.CreateInsertValue(Ret, NewField,
I);
501 for (
auto [Idx, FromPart, ToPart] :
503 Value *
Field = IRB.CreateExtractValue(V, Idx);
505 fatPtrsToInts(
Field, FromPart, ToPart, Name +
"." + Twine(Idx));
506 Ret = IRB.CreateInsertValue(Ret, NewField, Idx);
509 ConvertedForStore[
V] = Ret;
513Value *StoreFatPtrsAsIntsAndExpandMemcpyVisitor::intsToFatPtrs(
518 Value *Cast = IRB.CreateIntToPtr(V, To, Name +
".ptr");
528 for (uint64_t
I = 0,
E = AT->getArrayNumElements();
I <
E; ++
I) {
531 intsToFatPtrs(
Field, FromPart, ToPart, Name +
"." + Twine(
I));
532 Ret = IRB.CreateInsertValue(Ret, NewField,
I);
535 for (
auto [Idx, FromPart, ToPart] :
537 Value *
Field = IRB.CreateExtractValue(V, Idx);
539 intsToFatPtrs(
Field, FromPart, ToPart, Name +
"." + Twine(Idx));
540 Ret = IRB.CreateInsertValue(Ret, NewField, Idx);
546bool StoreFatPtrsAsIntsAndExpandMemcpyVisitor::processFunction(
547 Function &
F,
const TargetTransformInfo *
TTI, ScalarEvolution *SE) {
563 ConvertedForStore.
clear();
569bool StoreFatPtrsAsIntsAndExpandMemcpyVisitor::visitAllocaInst(AllocaInst &
I) {
570 Type *Ty =
I.getAllocatedType();
571 Type *NewTy = TypeMap->remapType(Ty);
574 I.setAllocatedType(NewTy);
578bool StoreFatPtrsAsIntsAndExpandMemcpyVisitor::visitGetElementPtrInst(
579 GetElementPtrInst &
I) {
580 Type *Ty =
I.getSourceElementType();
581 Type *NewTy = TypeMap->remapType(Ty);
586 I.setSourceElementType(NewTy);
587 I.setResultElementType(TypeMap->remapType(
I.getResultElementType()));
591bool StoreFatPtrsAsIntsAndExpandMemcpyVisitor::visitLoadInst(LoadInst &LI) {
593 Type *IntTy = TypeMap->remapType(Ty);
597 IRB.SetInsertPoint(&LI);
599 NLI->mutateType(IntTy);
600 NLI = IRB.Insert(NLI);
603 Value *CastBack = intsToFatPtrs(NLI, IntTy, Ty, NLI->getName());
609bool StoreFatPtrsAsIntsAndExpandMemcpyVisitor::visitStoreInst(StoreInst &SI) {
611 Type *Ty =
V->getType();
612 Type *IntTy = TypeMap->remapType(Ty);
616 IRB.SetInsertPoint(&SI);
617 Value *IntV = fatPtrsToInts(V, Ty, IntTy,
V->getName());
621 SI.setOperand(0, IntV);
625bool StoreFatPtrsAsIntsAndExpandMemcpyVisitor::visitMemCpyInst(
637bool StoreFatPtrsAsIntsAndExpandMemcpyVisitor::visitMemMoveInst(
643 "memmove() on buffer descriptors is not implemented because pointer "
644 "comparison on buffer descriptors isn't implemented\n");
647bool StoreFatPtrsAsIntsAndExpandMemcpyVisitor::visitMemSetInst(
656bool StoreFatPtrsAsIntsAndExpandMemcpyVisitor::visitMemSetPatternInst(
657 MemSetPatternInst &MSPI) {
686class LegalizeBufferContentTypesVisitor
687 :
public InstVisitor<LegalizeBufferContentTypesVisitor, bool> {
688 friend class InstVisitor<LegalizeBufferContentTypesVisitor, bool>;
692 const DataLayout &
DL;
694 ScalarEvolution *SE =
nullptr;
704 const TargetMachine *TM;
705 const GCNSubtarget *ST =
nullptr;
709 Type *scalarArrayTypeAsVector(
Type *MaybeArrayType);
710 Value *arrayToVector(
Value *V,
Type *TargetType,
const Twine &Name);
711 Value *vectorToArray(
Value *V,
Type *OrigType,
const Twine &Name);
715 struct OobProperties {
717 bool NoWrapFromMax =
false;
719 bool NoPartialOOB =
false;
721 OobProperties() =
delete;
723 OobProperties(
bool NoWrapFromMax,
bool NoPartialOOB)
724 : NoWrapFromMax(NoWrapFromMax), NoPartialOOB(NoPartialOOB) {}
726 OobProperties analyzeOobProperties(
Value *Ptr,
Type *Ty, uint64_t ByteOffset);
754 uint64_t maxIntrinsicWidth(
Type *Ty, Align
A, OobProperties OobProps);
760 Type *legalNonAggregateForMemOp(
Type *
T, uint64_t MaxWidth);
761 Value *makeLegalNonAggregate(
Value *V,
Type *TargetType,
const Twine &Name);
762 Value *makeIllegalNonAggregate(
Value *V,
Type *OrigType,
const Twine &Name);
775 void getVecSlices(
Type *
T, uint64_t MaxWidth,
776 SmallVectorImpl<VecSlice> &Slices);
778 Value *extractSlice(
Value *Vec, VecSlice S,
const Twine &Name);
779 Value *insertSlice(
Value *Whole,
Value *Part, VecSlice S,
const Twine &Name);
789 Type *intrinsicTypeFor(
Type *LegalType);
791 bool visitLoadImpl(LoadInst &OrigLI,
Type *PartType,
792 SmallVectorImpl<uint32_t> &AggIdxs, uint64_t AggByteOffset,
793 Value *&Result,
const Twine &Name);
795 std::pair<bool, bool> visitStoreImpl(StoreInst &OrigSI,
Type *PartType,
796 SmallVectorImpl<uint32_t> &AggIdxs,
797 uint64_t AggByteOffset,
800 bool visitInstruction(Instruction &
I) {
return false; }
801 bool visitLoadInst(LoadInst &LI);
802 bool visitStoreInst(StoreInst &SI);
805 bool visitIntrinsicInst(IntrinsicInst &
II);
806 bool visitAddrSpaceCastInst(AddrSpaceCastInst &ASCI);
809 LegalizeBufferContentTypesVisitor(
const DataLayout &
DL, LLVMContext &Ctx,
810 const TargetMachine *TM)
811 : IRB(Ctx, InstSimplifyFolder(
DL)),
DL(
DL), TM(TM) {}
816Type *LegalizeBufferContentTypesVisitor::scalarArrayTypeAsVector(
Type *
T) {
820 Type *ET = AT->getElementType();
823 "should have recursed");
824 if (!
DL.typeSizeEqualsStoreSize(AT))
826 "loading padded arrays from buffer fat pinters should have recursed");
830Value *LegalizeBufferContentTypesVisitor::arrayToVector(
Value *V,
835 unsigned EC = VT->getNumElements();
836 for (
auto I : iota_range<unsigned>(0, EC,
false)) {
837 Value *Elem = IRB.CreateExtractValue(V,
I, Name +
".elem." + Twine(
I));
838 VectorRes = IRB.CreateInsertElement(VectorRes, Elem,
I,
839 Name +
".as.vec." + Twine(
I));
844Value *LegalizeBufferContentTypesVisitor::vectorToArray(
Value *V,
849 unsigned EC = AT->getNumElements();
850 for (
auto I : iota_range<unsigned>(0, EC,
false)) {
851 Value *Elem = IRB.CreateExtractElement(V,
I, Name +
".elem." + Twine(
I));
852 ArrayRes = IRB.CreateInsertValue(ArrayRes, Elem,
I,
853 Name +
".as.array." + Twine(
I));
858LegalizeBufferContentTypesVisitor::OobProperties
859LegalizeBufferContentTypesVisitor::analyzeOobProperties(
Value *Ptr,
Type *Ty,
860 uint64_t ByteOffset) {
861 OobProperties
Result(
false,
false);
864 return OobProperties(
true,
true);
870 const SCEV *PtrOp = SE->
getSCEV(Ptr);
876 Value *PtrBaseVal = PtrBase->getValue();
883 auto NumRecordsIfKnown = ZeroBasePointerToNumRecords.
find(PtrBaseVal);
884 if (NumRecordsIfKnown == ZeroBasePointerToNumRecords.
end())
887 unsigned TypeSize =
DL.getTypeStoreSize(Ty).getKnownMinValue();
892 Result.NoWrapFromMax =
true;
896 if (!NumRecordsIfKnown->second)
898 const SCEV *NumRecords = SE->
getSCEV(NumRecordsIfKnown->second);
902 Result.NoPartialOOB =
true;
904 const SCEV *BoundsDiff;
905 if (ST->has45BitNumRecordsBufferResource()) {
906 const SCEV *PtrDiffExt =
910 const SCEV *NumRecordsI32 =
917 Result.NoPartialOOB =
true;
922LegalizeBufferContentTypesVisitor::maxIntrinsicWidth(
Type *
T, Align
A,
923 OobProperties OobProps) {
929 TypeSize ElemBits =
DL.getTypeSizeInBits(VT->getElementType());
936 if (!OobProps.NoWrapFromMax)
955 if (!OobProps.NoPartialOOB)
960 return Result.value() * 8;
963Type *LegalizeBufferContentTypesVisitor::legalNonAggregateForMemOp(
964 Type *
T, uint64_t MaxWidth) {
965 TypeSize
Size =
DL.getTypeStoreSizeInBits(
T);
967 if (!
DL.typeSizeEqualsStoreSize(
T))
968 T = IRB.getIntNTy(
Size.getFixedValue());
969 Type *ElemTy =
T->getScalarType();
975 unsigned ElemSize =
DL.getTypeSizeInBits(ElemTy).getFixedValue();
976 if (
isPowerOf2_32(ElemSize) && ElemSize >= 16 && ElemSize <= MaxWidth) {
982 Type *BestVectorElemType =
nullptr;
983 if (
Size.isKnownMultipleOf(32) && MaxWidth >= 32)
984 BestVectorElemType = IRB.getInt32Ty();
985 else if (
Size.isKnownMultipleOf(16) && MaxWidth >= 16)
986 BestVectorElemType = IRB.getInt16Ty();
988 BestVectorElemType = IRB.getInt8Ty();
989 unsigned NumCastElems =
991 if (NumCastElems == 1)
992 return BestVectorElemType;
996Value *LegalizeBufferContentTypesVisitor::makeLegalNonAggregate(
997 Value *V,
Type *TargetType,
const Twine &Name) {
998 Type *SourceType =
V->getType();
999 TypeSize SourceSize =
DL.getTypeSizeInBits(SourceType);
1000 TypeSize TargetSize =
DL.getTypeSizeInBits(TargetType);
1001 if (SourceSize != TargetSize) {
1004 Value *AsScalar = IRB.CreateBitCast(V, ShortScalarTy, Name +
".as.scalar");
1005 Value *Zext = IRB.CreateZExt(AsScalar, ByteScalarTy, Name +
".zext");
1007 SourceType = ByteScalarTy;
1009 return IRB.CreateBitCast(V, TargetType, Name +
".legal");
1012Value *LegalizeBufferContentTypesVisitor::makeIllegalNonAggregate(
1013 Value *V,
Type *OrigType,
const Twine &Name) {
1014 Type *LegalType =
V->getType();
1015 TypeSize LegalSize =
DL.getTypeSizeInBits(LegalType);
1016 TypeSize OrigSize =
DL.getTypeSizeInBits(OrigType);
1017 if (LegalSize != OrigSize) {
1020 Value *AsScalar = IRB.CreateBitCast(V, ByteScalarTy, Name +
".bytes.cast");
1021 Value *Trunc = IRB.CreateTrunc(AsScalar, ShortScalarTy, Name +
".trunc");
1022 return IRB.CreateBitCast(Trunc, OrigType, Name +
".orig");
1024 return IRB.CreateBitCast(V, OrigType, Name +
".real.ty");
1027Type *LegalizeBufferContentTypesVisitor::intrinsicTypeFor(
Type *LegalType) {
1031 Type *ET = VT->getElementType();
1034 if (VT->getNumElements() == 1)
1036 if (
DL.getTypeSizeInBits(LegalType) == 96 &&
DL.getTypeSizeInBits(ET) < 32)
1039 switch (VT->getNumElements()) {
1043 return IRB.getInt8Ty();
1045 return IRB.getInt16Ty();
1047 return IRB.getInt32Ty();
1057void LegalizeBufferContentTypesVisitor::getVecSlices(
1058 Type *
T, uint64_t MaxWidth, SmallVectorImpl<VecSlice> &Slices) {
1064 uint64_t ElemBitWidth =
1065 DL.getTypeSizeInBits(VT->getElementType()).getFixedValue();
1067 uint64_t ElemsPer4Words = 128 / ElemBitWidth;
1068 uint64_t ElemsPer2Words = ElemsPer4Words / 2;
1069 uint64_t ElemsPerWord = ElemsPer2Words / 2;
1070 uint64_t ElemsPerShort = ElemsPerWord / 2;
1071 uint64_t ElemsPerByte = ElemsPerShort / 2;
1075 uint64_t ElemsPer3Words = ElemsPerWord * 3;
1077 uint64_t TotalElems = VT->getNumElements();
1079 auto TrySlice = [&](
unsigned MaybeLen,
unsigned Width) {
1080 if (MaybeLen > 0 && Width <= MaxWidth && Index + MaybeLen <= TotalElems) {
1081 VecSlice Slice{
Index, MaybeLen};
1088 while (Index < TotalElems) {
1089 TrySlice(ElemsPer4Words, 128) || TrySlice(ElemsPer3Words, 96) ||
1090 TrySlice(ElemsPer2Words, 64) || TrySlice(ElemsPerWord, 32) ||
1091 TrySlice(ElemsPerShort, 16) || TrySlice(ElemsPerByte, 8);
1095Value *LegalizeBufferContentTypesVisitor::extractSlice(
Value *Vec, VecSlice S,
1096 const Twine &Name) {
1100 if (S.Length == VecVT->getNumElements() && S.Index == 0)
1103 return IRB.CreateExtractElement(Vec, S.Index,
1104 Name +
".slice." + Twine(S.Index));
1106 llvm::iota_range<int>(S.Index, S.Index + S.Length,
false));
1107 return IRB.CreateShuffleVector(Vec, Mask, Name +
".slice." + Twine(S.Index));
1110Value *LegalizeBufferContentTypesVisitor::insertSlice(
Value *Whole,
Value *Part,
1112 const Twine &Name) {
1116 if (S.Length == WholeVT->getNumElements() && S.Index == 0)
1118 if (S.Length == 1) {
1119 return IRB.CreateInsertElement(Whole, Part, S.Index,
1120 Name +
".slice." + Twine(S.Index));
1125 SmallVector<int> ExtPartMask(NumElems, -1);
1130 Value *ExtPart = IRB.CreateShuffleVector(Part, ExtPartMask,
1131 Name +
".ext." + Twine(S.Index));
1133 SmallVector<int>
Mask =
1138 return IRB.CreateShuffleVector(Whole, ExtPart, Mask,
1139 Name +
".parts." + Twine(S.Index));
1142bool LegalizeBufferContentTypesVisitor::visitLoadImpl(
1143 LoadInst &OrigLI,
Type *PartType, SmallVectorImpl<uint32_t> &AggIdxs,
1144 uint64_t AggByteOff,
Value *&Result,
const Twine &Name) {
1146 const StructLayout *Layout =
DL.getStructLayout(ST);
1148 for (
auto [
I, ElemTy,
Offset] :
1151 Changed |= visitLoadImpl(OrigLI, ElemTy, AggIdxs,
1152 AggByteOff +
Offset.getFixedValue(), Result,
1153 Name +
"." + Twine(
I));
1159 Type *ElemTy = AT->getElementType();
1162 TypeSize ElemAllocSize =
DL.getTypeAllocSize(ElemTy);
1164 for (
auto I : llvm::iota_range<uint32_t>(0, AT->getNumElements(),
1167 Changed |= visitLoadImpl(OrigLI, ElemTy, AggIdxs,
1169 Result, Name + Twine(
I));
1179 Type *ArrayAsVecType = scalarArrayTypeAsVector(PartType);
1180 OobProperties OobProps =
1182 uint64_t MaxWidth = maxIntrinsicWidth(ArrayAsVecType, PartAlign, OobProps);
1183 Type *LegalType = legalNonAggregateForMemOp(ArrayAsVecType, MaxWidth);
1186 getVecSlices(LegalType, MaxWidth, Slices);
1187 bool HasSlices = Slices.
size() > 1;
1188 bool IsAggPart = !AggIdxs.
empty();
1190 if (!HasSlices && !IsAggPart) {
1191 Type *LoadableType = intrinsicTypeFor(LegalType);
1192 if (LoadableType == PartType)
1195 IRB.SetInsertPoint(&OrigLI);
1197 NLI->mutateType(LoadableType);
1198 NLI = IRB.Insert(NLI);
1199 NLI->setName(Name +
".loadable");
1201 LoadsRes = IRB.CreateBitCast(NLI, LegalType, Name +
".from.loadable");
1203 IRB.SetInsertPoint(&OrigLI);
1211 unsigned ElemBytes =
DL.getTypeStoreSize(ElemType);
1213 if (IsAggPart && Slices.
empty())
1215 for (VecSlice S : Slices) {
1218 int64_t ByteOffset = AggByteOff + S.Index * ElemBytes;
1220 Value *NewPtr = IRB.CreateGEP(
1222 OrigPtr->
getName() +
".off.ptr." + Twine(ByteOffset),
1225 Type *LoadableType = intrinsicTypeFor(SliceType);
1226 LoadInst *NewLI = IRB.CreateAlignedLoad(
1228 Name +
".off." + Twine(ByteOffset));
1234 Value *
Loaded = IRB.CreateBitCast(NewLI, SliceType,
1235 NewLI->
getName() +
".from.loadable");
1236 LoadsRes = insertSlice(LoadsRes, Loaded, S, Name);
1239 if (LegalType != ArrayAsVecType)
1240 LoadsRes = makeIllegalNonAggregate(LoadsRes, ArrayAsVecType, Name);
1241 if (ArrayAsVecType != PartType)
1242 LoadsRes = vectorToArray(LoadsRes, PartType, Name);
1245 Result = IRB.CreateInsertValue(Result, LoadsRes, AggIdxs, Name);
1251bool LegalizeBufferContentTypesVisitor::visitLoadInst(LoadInst &LI) {
1255 SmallVector<uint32_t> AggIdxs;
1258 bool Changed = visitLoadImpl(LI, OrigType, AggIdxs, 0, Result, LI.
getName());
1267std::pair<bool, bool> LegalizeBufferContentTypesVisitor::visitStoreImpl(
1268 StoreInst &OrigSI,
Type *PartType, SmallVectorImpl<uint32_t> &AggIdxs,
1269 uint64_t AggByteOff,
const Twine &Name) {
1271 const StructLayout *Layout =
DL.getStructLayout(ST);
1273 for (
auto [
I, ElemTy,
Offset] :
1276 Changed |= std::get<0>(visitStoreImpl(OrigSI, ElemTy, AggIdxs,
1277 AggByteOff +
Offset.getFixedValue(),
1278 Name +
"." + Twine(
I)));
1281 return std::make_pair(
Changed,
false);
1284 Type *ElemTy = AT->getElementType();
1287 TypeSize ElemAllocSize =
DL.getTypeAllocSize(ElemTy);
1289 for (
auto I : llvm::iota_range<uint32_t>(0, AT->getNumElements(),
1292 Changed |= std::get<0>(visitStoreImpl(
1293 OrigSI, ElemTy, AggIdxs,
1297 return std::make_pair(
Changed,
false);
1302 Value *NewData = OrigData;
1304 bool IsAggPart = !AggIdxs.
empty();
1306 NewData = IRB.CreateExtractValue(NewData, AggIdxs, Name);
1308 Type *ArrayAsVecType = scalarArrayTypeAsVector(PartType);
1309 if (ArrayAsVecType != PartType) {
1310 NewData = arrayToVector(NewData, ArrayAsVecType, Name);
1314 OobProperties OobProps =
1316 uint64_t MaxWidth = maxIntrinsicWidth(ArrayAsVecType, PartAlign, OobProps);
1317 Type *LegalType = legalNonAggregateForMemOp(ArrayAsVecType, MaxWidth);
1318 if (LegalType != ArrayAsVecType) {
1319 NewData = makeLegalNonAggregate(NewData, LegalType, Name);
1323 getVecSlices(LegalType, MaxWidth, Slices);
1324 bool NeedToSplit = Slices.
size() > 1 || IsAggPart;
1326 Type *StorableType = intrinsicTypeFor(LegalType);
1327 if (StorableType == PartType)
1328 return std::make_pair(
false,
false);
1329 NewData = IRB.CreateBitCast(NewData, StorableType, Name +
".storable");
1331 return std::make_pair(
true,
true);
1336 if (IsAggPart && Slices.
empty())
1338 unsigned ElemBytes =
DL.getTypeStoreSize(ElemType);
1340 for (VecSlice S : Slices) {
1343 int64_t ByteOffset = AggByteOff + S.Index * ElemBytes;
1344 Value *NewPtr = IRB.CreateGEP(
1345 IRB.getInt8Ty(), OrigPtr, IRB.getInt32(ByteOffset),
1346 OrigPtr->
getName() +
".part." + Twine(S.Index),
1349 Value *DataSlice = extractSlice(NewData, S, Name);
1350 Type *StorableType = intrinsicTypeFor(SliceType);
1351 DataSlice = IRB.CreateBitCast(DataSlice, StorableType,
1352 DataSlice->
getName() +
".storable");
1356 NewSI->setOperand(0, DataSlice);
1357 NewSI->setOperand(1, NewPtr);
1360 return std::make_pair(
true,
false);
1363bool LegalizeBufferContentTypesVisitor::visitStoreInst(StoreInst &SI) {
1366 IRB.SetInsertPoint(&SI);
1367 SmallVector<uint32_t> AggIdxs;
1368 Value *OrigData =
SI.getValueOperand();
1369 auto [
Changed, ModifiedInPlace] =
1370 visitStoreImpl(SI, OrigData->
getType(), AggIdxs, 0, OrigData->
getName());
1371 if (
Changed && !ModifiedInPlace)
1372 SI.eraseFromParent();
1376bool LegalizeBufferContentTypesVisitor::visitAddrSpaceCastInst(
1377 AddrSpaceCastInst &AI) {
1382 auto Record = ZeroBasePointerToNumRecords.
find(Src);
1383 if (Record != ZeroBasePointerToNumRecords.
end())
1384 ZeroBasePointerToNumRecords.
insert({&AI,
Record->second});
1386 ZeroBasePointerToNumRecords.
insert({&AI,
nullptr});
1390bool LegalizeBufferContentTypesVisitor::visitIntrinsicInst(IntrinsicInst &
II) {
1391 if (
II.getIntrinsicID() != Intrinsic::amdgcn_make_buffer_rsrc)
1393 ZeroBasePointerToNumRecords.
insert({&
II,
II.getOperand(2)});
1397bool LegalizeBufferContentTypesVisitor::processFunction(Function &
F,
1398 ScalarEvolution *SE) {
1405 ZeroBasePointerToNumRecords.
clear();
1412static std::pair<Constant *, Constant *>
1415 return std::make_pair(
C->getAggregateElement(0u),
C->getAggregateElement(1u));
1420class FatPtrConstMaterializer final :
public ValueMaterializer {
1421 BufferFatPtrToStructTypeMap *TypeMap;
1427 ValueMapper InternalMapper;
1429 Constant *materializeBufferFatPtrConst(Constant *
C);
1433 FatPtrConstMaterializer(BufferFatPtrToStructTypeMap *TypeMap,
1436 InternalMapper(UnderlyingMap,
RF_None, TypeMap, this) {}
1437 ~FatPtrConstMaterializer() =
default;
1443Constant *FatPtrConstMaterializer::materializeBufferFatPtrConst(Constant *
C) {
1444 Type *SrcTy =
C->getType();
1446 if (
C->isNullValue())
1447 return ConstantAggregateZero::getNullValue(NewTy);
1460 if (Constant *S =
VC->getSplatValue()) {
1465 auto EC =
VC->getType()->getElementCount();
1471 for (
Value *
Op :
VC->operand_values()) {
1486 "fat pointer) values are not supported");
1490 "constant exprs containing ptr addrspace(7) (buffer "
1491 "fat pointer) values should have been expanded earlier");
1496Value *FatPtrConstMaterializer::materialize(
Value *V) {
1504 return materializeBufferFatPtrConst(
C);
1512class SplitPtrStructs :
public InstVisitor<SplitPtrStructs, PtrParts> {
1555 void processConditionals();
1605void SplitPtrStructs::copyMetadata(
Value *Dest,
Value *Src) {
1609 if (!DestI || !SrcI)
1612 DestI->copyMetadata(*SrcI);
1617 "of something that wasn't rewritten");
1618 auto *RsrcEntry = &RsrcParts[
V];
1619 auto *OffEntry = &OffParts[
V];
1620 if (*RsrcEntry && *OffEntry)
1621 return {*RsrcEntry, *OffEntry};
1625 return {*RsrcEntry = Rsrc, *OffEntry =
Off};
1628 IRBuilder<InstSimplifyFolder>::InsertPointGuard Guard(IRB);
1633 return {*RsrcEntry = Rsrc, *OffEntry =
Off};
1636 IRB.SetInsertPoint(*
I->getInsertionPointAfterDef());
1637 IRB.SetCurrentDebugLocation(
I->getDebugLoc());
1639 IRB.SetInsertPointPastAllocas(
A->getParent());
1640 IRB.SetCurrentDebugLocation(
DebugLoc());
1642 Value *Rsrc = IRB.CreateExtractValue(V, 0,
V->getName() +
".rsrc");
1643 Value *
Off = IRB.CreateExtractValue(V, 1,
V->getName() +
".off");
1644 return {*RsrcEntry = Rsrc, *OffEntry =
Off};
1657 V =
GEP->getPointerOperand();
1659 V = ASC->getPointerOperand();
1663void SplitPtrStructs::getPossibleRsrcRoots(Instruction *
I,
1664 SmallPtrSetImpl<Value *> &Roots,
1665 SmallPtrSetImpl<Value *> &Seen) {
1669 for (
Value *In :
PHI->incoming_values()) {
1676 if (!Seen.
insert(SI).second)
1691void SplitPtrStructs::processConditionals() {
1692 SmallDenseMap<Value *, Value *> FoundRsrcs;
1693 SmallPtrSet<Value *, 4> Roots;
1694 SmallPtrSet<Value *, 4> Seen;
1695 for (Instruction *
I : Conditionals) {
1697 Value *Rsrc = RsrcParts[
I];
1699 assert(Rsrc && Off &&
"must have visited conditionals by now");
1701 std::optional<Value *> MaybeRsrc;
1702 auto MaybeFoundRsrc = FoundRsrcs.
find(
I);
1703 if (MaybeFoundRsrc != FoundRsrcs.
end()) {
1704 MaybeRsrc = MaybeFoundRsrc->second;
1706 IRBuilder<InstSimplifyFolder>::InsertPointGuard Guard(IRB);
1709 getPossibleRsrcRoots(
I, Roots, Seen);
1712 for (
Value *V : Roots)
1714 for (
Value *V : Seen)
1726 if (Diff.size() == 1) {
1727 Value *RootVal = *Diff.begin();
1731 MaybeRsrc = std::get<0>(getPtrParts(RootVal));
1733 MaybeRsrc = RootVal;
1741 IRB.SetInsertPoint(*
PHI->getInsertionPointAfterDef());
1742 IRB.SetCurrentDebugLocation(
PHI->getDebugLoc());
1744 NewRsrc = *MaybeRsrc;
1747 auto *RsrcPHI = IRB.CreatePHI(RsrcTy,
PHI->getNumIncomingValues());
1748 RsrcPHI->takeName(Rsrc);
1749 for (
auto [V, BB] :
llvm::zip(
PHI->incoming_values(),
PHI->blocks())) {
1750 Value *VRsrc = std::get<0>(getPtrParts(V));
1751 RsrcPHI->addIncoming(VRsrc, BB);
1753 copyMetadata(RsrcPHI,
PHI);
1758 auto *NewOff = IRB.CreatePHI(OffTy,
PHI->getNumIncomingValues());
1759 NewOff->takeName(Off);
1760 for (
auto [V, BB] :
llvm::zip(
PHI->incoming_values(),
PHI->blocks())) {
1761 assert(OffParts.
count(V) &&
"An offset part had to be created by now");
1762 Value *VOff = std::get<1>(getPtrParts(V));
1763 NewOff->addIncoming(VOff, BB);
1765 copyMetadata(NewOff,
PHI);
1774 ConditionalTemps.push_back(RsrcInst);
1775 RsrcInst->replaceAllUsesWith(NewRsrc);
1778 ConditionalTemps.push_back(OffInst);
1779 OffInst->replaceAllUsesWith(NewOff);
1784 for (
Value *V : Seen)
1785 FoundRsrcs[
V] = NewRsrc;
1790 if (RsrcInst != *MaybeRsrc) {
1791 ConditionalTemps.push_back(RsrcInst);
1792 RsrcInst->replaceAllUsesWith(*MaybeRsrc);
1795 for (
Value *V : Seen)
1796 FoundRsrcs[
V] = *MaybeRsrc;
1804void SplitPtrStructs::killAndReplaceSplitInstructions(
1805 SmallVectorImpl<Instruction *> &Origs) {
1806 for (Instruction *
I : ConditionalTemps)
1807 I->eraseFromParent();
1809 for (Instruction *
I : Origs) {
1815 for (DbgVariableRecord *Dbg : Dbgs) {
1816 auto &
DL =
I->getDataLayout();
1818 "We should've RAUW'd away loads, stores, etc. at this point");
1819 DbgVariableRecord *OffDbg =
Dbg->clone();
1820 auto [Rsrc,
Off] = getPtrParts(
I);
1822 int64_t RsrcSz =
DL.getTypeSizeInBits(Rsrc->
getType());
1823 int64_t OffSz =
DL.getTypeSizeInBits(
Off->getType());
1825 std::optional<DIExpression *> RsrcExpr =
1828 std::optional<DIExpression *> OffExpr =
1839 Dbg->setExpression(*RsrcExpr);
1840 Dbg->replaceVariableLocationOp(
I, Rsrc);
1847 I->replaceUsesWithIf(
Poison, [&](
const Use &U) ->
bool {
1853 if (
I->use_empty()) {
1854 I->eraseFromParent();
1857 IRB.SetInsertPoint(*
I->getInsertionPointAfterDef());
1858 IRB.SetCurrentDebugLocation(
I->getDebugLoc());
1859 auto [Rsrc,
Off] = getPtrParts(
I);
1861 Struct = IRB.CreateInsertValue(Struct, Rsrc, 0);
1862 Struct = IRB.CreateInsertValue(Struct, Off, 1);
1863 copyMetadata(Struct,
I);
1865 I->replaceAllUsesWith(Struct);
1866 I->eraseFromParent();
1870void SplitPtrStructs::setAlign(CallInst *Intr, Align
A,
unsigned RsrcArgIdx) {
1872 Intr->
addParamAttr(RsrcArgIdx, Attribute::getWithAlignment(Ctx,
A));
1878 case AtomicOrdering::Release:
1879 case AtomicOrdering::AcquireRelease:
1880 case AtomicOrdering::SequentiallyConsistent:
1881 IRB.CreateFence(AtomicOrdering::Release, SSID);
1891 case AtomicOrdering::Acquire:
1892 case AtomicOrdering::AcquireRelease:
1893 case AtomicOrdering::SequentiallyConsistent:
1894 IRB.CreateFence(AtomicOrdering::Acquire, SSID);
1901Value *SplitPtrStructs::handleMemoryInst(Instruction *
I,
Value *Arg,
Value *Ptr,
1902 Type *Ty, Align Alignment,
1905 IRB.SetInsertPoint(
I);
1907 auto [Rsrc,
Off] = getPtrParts(Ptr);
1910 Args.push_back(Arg);
1911 Args.push_back(Rsrc);
1912 Args.push_back(Off);
1913 insertPreMemOpFence(Order, SSID);
1917 Args.push_back(IRB.getInt32(0));
1922 Args.push_back(IRB.getInt32(Aux));
1926 IID = Order == AtomicOrdering::NotAtomic
1927 ? Intrinsic::amdgcn_raw_ptr_buffer_load
1928 : Intrinsic::amdgcn_raw_ptr_atomic_buffer_load;
1930 IID = Intrinsic::amdgcn_raw_ptr_buffer_store;
1932 switch (RMW->getOperation()) {
1934 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_swap;
1937 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_add;
1940 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_sub;
1943 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_and;
1946 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_or;
1949 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_xor;
1952 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_smax;
1955 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_smin;
1958 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_umax;
1961 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_umin;
1964 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_fadd;
1967 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_fmax;
1970 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_fmin;
1973 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_cond_sub_u32;
1976 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_sub_clamp_u32;
1980 "atomic floating point subtraction not supported for "
1981 "buffer resources and should've been expanded away");
1986 "atomic floating point fmaximum not supported for "
1987 "buffer resources and should've been expanded away");
1992 "atomic floating point fminimum not supported for "
1993 "buffer resources and should've been expanded away");
1998 "atomic floating point fmaximumnum not supported for "
1999 "buffer resources and should've been expanded away");
2004 "atomic floating point fminimumnum not supported for "
2005 "buffer resources and should've been expanded away");
2010 "atomic nand not supported for buffer resources and "
2011 "should've been expanded away");
2016 "wrapping increment/decrement not supported for "
2017 "buffer resources and should've been expanded away");
2024 CallInst *
Call = IRB.CreateIntrinsicWithoutFolding(IID, Ty, Args);
2025 copyMetadata(
Call,
I);
2026 setAlign(
Call, Alignment, Arg ? 1 : 0);
2029 insertPostMemOpFence(Order, SSID);
2033 I->replaceAllUsesWith(
Call);
2037PtrParts SplitPtrStructs::visitInstruction(Instruction &
I) {
2038 return {
nullptr,
nullptr};
2041PtrParts SplitPtrStructs::visitLoadInst(LoadInst &LI) {
2043 return {
nullptr,
nullptr};
2047 return {
nullptr,
nullptr};
2050PtrParts SplitPtrStructs::visitStoreInst(StoreInst &SI) {
2052 return {
nullptr,
nullptr};
2053 Value *Arg =
SI.getValueOperand();
2054 handleMemoryInst(&SI, Arg,
SI.getPointerOperand(), Arg->
getType(),
2055 SI.getAlign(),
SI.getOrdering(),
SI.isVolatile(),
2056 SI.getSyncScopeID());
2057 return {
nullptr,
nullptr};
2060PtrParts SplitPtrStructs::visitAtomicRMWInst(AtomicRMWInst &AI) {
2062 return {
nullptr,
nullptr};
2067 return {
nullptr,
nullptr};
2072PtrParts SplitPtrStructs::visitAtomicCmpXchgInst(AtomicCmpXchgInst &AI) {
2075 return {
nullptr,
nullptr};
2076 IRB.SetInsertPoint(&AI);
2081 bool IsNonTemporal = AI.
getMetadata(LLVMContext::MD_nontemporal);
2083 auto [Rsrc,
Off] = getPtrParts(Ptr);
2084 insertPreMemOpFence(Order, SSID);
2091 CallInst *
Call = IRB.CreateIntrinsicWithoutFolding(
2092 Intrinsic::amdgcn_raw_ptr_buffer_atomic_cmpswap, Ty,
2094 IRB.getInt32(0), IRB.getInt32(Aux)});
2095 copyMetadata(
Call, &AI);
2098 insertPostMemOpFence(Order, SSID);
2101 Res = IRB.CreateInsertValue(Res,
Call, 0);
2103 Res = IRB.CreateInsertValue(Res, Succeeded, 1);
2106 return {
nullptr,
nullptr};
2109PtrParts SplitPtrStructs::visitGetElementPtrInst(GetElementPtrInst &
GEP) {
2110 using namespace llvm::PatternMatch;
2111 Value *Ptr =
GEP.getPointerOperand();
2113 return {
nullptr,
nullptr};
2114 IRB.SetInsertPoint(&
GEP);
2116 auto [Rsrc,
Off] = getPtrParts(Ptr);
2117 const DataLayout &
DL =
GEP.getDataLayout();
2118 bool IsNUW =
GEP.hasNoUnsignedWrap();
2119 bool IsNUSW =
GEP.hasNoUnsignedSignedWrap();
2130 GEP.mutateType(FatPtrTy);
2132 GEP.mutateType(ResTy);
2134 if (BroadcastsPtr) {
2135 Rsrc = IRB.CreateVectorSplat(ResRsrcVecTy->getElementCount(), Rsrc,
2137 Off = IRB.CreateVectorSplat(ResRsrcVecTy->getElementCount(), Off,
2145 bool HasNonNegativeOff =
false;
2147 HasNonNegativeOff = !CI->isNegative();
2153 NewOff = IRB.CreateAdd(Off, OffAccum,
"",
2154 IsNUW || (IsNUSW && HasNonNegativeOff),
2157 copyMetadata(NewOff, &
GEP);
2160 return {Rsrc, NewOff};
2163PtrParts SplitPtrStructs::visitPtrToIntInst(PtrToIntInst &PI) {
2166 return {
nullptr,
nullptr};
2167 IRB.SetInsertPoint(&PI);
2172 auto [Rsrc,
Off] = getPtrParts(Ptr);
2178 Res = IRB.CreateIntCast(Off, ResTy,
false,
2181 Value *RsrcInt = IRB.CreatePtrToInt(Rsrc, ResTy, PI.
getName() +
".rsrc");
2182 Value *Shl = IRB.CreateShl(
2185 "", Width >= FatPtrWidth, Width > FatPtrWidth);
2186 Value *OffCast = IRB.CreateIntCast(Off, ResTy,
false,
2188 Res = IRB.CreateOr(Shl, OffCast);
2191 copyMetadata(Res, &PI);
2195 return {
nullptr,
nullptr};
2198PtrParts SplitPtrStructs::visitPtrToAddrInst(PtrToAddrInst &PA) {
2201 return {
nullptr,
nullptr};
2202 IRB.SetInsertPoint(&PA);
2204 auto [Rsrc,
Off] = getPtrParts(Ptr);
2205 Value *Res = IRB.CreateIntCast(Off, PA.
getType(),
false);
2206 copyMetadata(Res, &PA);
2210 return {
nullptr,
nullptr};
2213PtrParts SplitPtrStructs::visitIntToPtrInst(IntToPtrInst &IP) {
2215 return {
nullptr,
nullptr};
2216 IRB.SetInsertPoint(&IP);
2225 Type *RsrcTy = RetTy->getElementType(0);
2226 Type *OffTy = RetTy->getElementType(1);
2227 Value *RsrcPart = IRB.CreateLShr(
2230 Value *RsrcInt = IRB.CreateIntCast(RsrcPart, RsrcIntTy,
false);
2231 Value *Rsrc = IRB.CreateIntToPtr(RsrcInt, RsrcTy, IP.
getName() +
".rsrc");
2233 IRB.CreateIntCast(
Int, OffTy,
false, IP.
getName() +
".off");
2235 copyMetadata(Rsrc, &IP);
2240PtrParts SplitPtrStructs::visitAddrSpaceCastInst(AddrSpaceCastInst &
I) {
2244 return {
nullptr,
nullptr};
2245 IRB.SetInsertPoint(&
I);
2248 if (
In->getType() ==
I.getType()) {
2249 auto [Rsrc,
Off] = getPtrParts(In);
2255 Type *RsrcTy = ResTy->getElementType(0);
2256 Type *OffTy = ResTy->getElementType(1);
2262 if (InConst && InConst->isNullValue()) {
2265 return {NullRsrc, ZeroOff};
2271 return {PoisonRsrc, PoisonOff};
2277 return {UndefRsrc, UndefOff};
2282 "only buffer resources (addrspace 8) and null/poison pointers can be "
2283 "cast to buffer fat pointers (addrspace 7)");
2285 return {
In, ZeroOff};
2288PtrParts SplitPtrStructs::visitICmpInst(ICmpInst &Cmp) {
2291 return {
nullptr,
nullptr};
2293 IRB.SetInsertPoint(&Cmp);
2294 ICmpInst::Predicate Pred =
Cmp.getPredicate();
2296 assert((Pred == ICmpInst::ICMP_EQ || Pred == ICmpInst::ICMP_NE) &&
2297 "Pointer comparison is only equal or unequal");
2298 auto [LhsRsrc, LhsOff] = getPtrParts(Lhs);
2299 auto [RhsRsrc, RhsOff] = getPtrParts(Rhs);
2300 Value *Res = IRB.CreateICmp(Pred, LhsOff, RhsOff);
2301 copyMetadata(Res, &Cmp);
2304 Cmp.replaceAllUsesWith(Res);
2305 return {
nullptr,
nullptr};
2308PtrParts SplitPtrStructs::visitFreezeInst(FreezeInst &
I) {
2310 return {
nullptr,
nullptr};
2311 IRB.SetInsertPoint(&
I);
2312 auto [Rsrc,
Off] = getPtrParts(
I.getOperand(0));
2314 Value *RsrcRes = IRB.CreateFreeze(Rsrc,
I.getName() +
".rsrc");
2315 copyMetadata(RsrcRes, &
I);
2316 Value *OffRes = IRB.CreateFreeze(Off,
I.getName() +
".off");
2317 copyMetadata(OffRes, &
I);
2319 return {RsrcRes, OffRes};
2322PtrParts SplitPtrStructs::visitExtractElementInst(ExtractElementInst &
I) {
2324 return {
nullptr,
nullptr};
2325 IRB.SetInsertPoint(&
I);
2326 Value *Vec =
I.getVectorOperand();
2327 Value *Idx =
I.getIndexOperand();
2328 auto [Rsrc,
Off] = getPtrParts(Vec);
2330 Value *RsrcRes = IRB.CreateExtractElement(Rsrc, Idx,
I.getName() +
".rsrc");
2331 copyMetadata(RsrcRes, &
I);
2332 Value *OffRes = IRB.CreateExtractElement(Off, Idx,
I.getName() +
".off");
2333 copyMetadata(OffRes, &
I);
2335 return {RsrcRes, OffRes};
2338PtrParts SplitPtrStructs::visitInsertElementInst(InsertElementInst &
I) {
2342 return {
nullptr,
nullptr};
2343 IRB.SetInsertPoint(&
I);
2344 Value *Vec =
I.getOperand(0);
2345 Value *Elem =
I.getOperand(1);
2346 Value *Idx =
I.getOperand(2);
2347 auto [VecRsrc, VecOff] = getPtrParts(Vec);
2348 auto [ElemRsrc, ElemOff] = getPtrParts(Elem);
2351 IRB.CreateInsertElement(VecRsrc, ElemRsrc, Idx,
I.getName() +
".rsrc");
2352 copyMetadata(RsrcRes, &
I);
2354 IRB.CreateInsertElement(VecOff, ElemOff, Idx,
I.getName() +
".off");
2355 copyMetadata(OffRes, &
I);
2357 return {RsrcRes, OffRes};
2360PtrParts SplitPtrStructs::visitShuffleVectorInst(ShuffleVectorInst &
I) {
2363 return {
nullptr,
nullptr};
2364 IRB.SetInsertPoint(&
I);
2367 Value *V2 =
I.getOperand(1);
2368 ArrayRef<int>
Mask =
I.getShuffleMask();
2369 auto [V1Rsrc, V1Off] = getPtrParts(
V1);
2370 auto [V2Rsrc, V2Off] = getPtrParts(V2);
2373 IRB.CreateShuffleVector(V1Rsrc, V2Rsrc, Mask,
I.getName() +
".rsrc");
2374 copyMetadata(RsrcRes, &
I);
2376 IRB.CreateShuffleVector(V1Off, V2Off, Mask,
I.getName() +
".off");
2377 copyMetadata(OffRes, &
I);
2379 return {RsrcRes, OffRes};
2382PtrParts SplitPtrStructs::visitPHINode(PHINode &
PHI) {
2384 return {
nullptr,
nullptr};
2385 IRB.SetInsertPoint(*
PHI.getInsertionPointAfterDef());
2391 Value *TmpRsrc = IRB.CreateExtractValue(&
PHI, 0,
PHI.getName() +
".rsrc");
2392 Value *TmpOff = IRB.CreateExtractValue(&
PHI, 1,
PHI.getName() +
".off");
2393 Conditionals.push_back(&
PHI);
2395 return {TmpRsrc, TmpOff};
2398PtrParts SplitPtrStructs::visitSelectInst(SelectInst &SI) {
2400 return {
nullptr,
nullptr};
2401 IRB.SetInsertPoint(&SI);
2404 Value *True =
SI.getTrueValue();
2405 Value *False =
SI.getFalseValue();
2406 auto [TrueRsrc, TrueOff] = getPtrParts(True);
2407 auto [FalseRsrc, FalseOff] = getPtrParts(False);
2410 IRB.CreateSelect(
Cond, TrueRsrc, FalseRsrc,
SI.getName() +
".rsrc", &SI);
2411 copyMetadata(RsrcRes, &SI);
2412 Conditionals.push_back(&SI);
2414 IRB.CreateSelect(
Cond, TrueOff, FalseOff,
SI.getName() +
".off", &SI);
2415 copyMetadata(OffRes, &SI);
2417 return {RsrcRes, OffRes};
2428 case Intrinsic::amdgcn_make_buffer_rsrc:
2429 case Intrinsic::ptrmask:
2430 case Intrinsic::invariant_start:
2431 case Intrinsic::invariant_end:
2432 case Intrinsic::launder_invariant_group:
2433 case Intrinsic::strip_invariant_group:
2434 case Intrinsic::memcpy:
2435 case Intrinsic::memcpy_inline:
2436 case Intrinsic::memmove:
2437 case Intrinsic::memset:
2438 case Intrinsic::memset_inline:
2439 case Intrinsic::experimental_memset_pattern:
2440 case Intrinsic::amdgcn_load_to_lds:
2441 case Intrinsic::amdgcn_load_async_to_lds:
2446PtrParts SplitPtrStructs::visitIntrinsicInst(IntrinsicInst &
I) {
2451 case Intrinsic::amdgcn_make_buffer_rsrc: {
2453 return {
nullptr,
nullptr};
2455 Value *Stride =
I.getArgOperand(1);
2456 Value *NumRecords =
I.getArgOperand(2);
2459 Type *RsrcType = SplitType->getElementType(0);
2460 Type *OffType = SplitType->getElementType(1);
2461 IRB.SetInsertPoint(&
I);
2462 Value *Rsrc = IRB.CreateIntrinsic(IID, {RsrcType,
Base->getType()},
2464 copyMetadata(Rsrc, &
I);
2468 return {Rsrc,
Zero};
2470 case Intrinsic::ptrmask: {
2471 Value *Ptr =
I.getArgOperand(0);
2473 return {
nullptr,
nullptr};
2475 IRB.SetInsertPoint(&
I);
2476 auto [Rsrc,
Off] = getPtrParts(Ptr);
2477 if (
Mask->getType() !=
Off->getType())
2479 "pointer (data layout not set up correctly?)");
2480 Value *OffRes = IRB.CreateAnd(Off, Mask,
I.getName() +
".off");
2481 copyMetadata(OffRes, &
I);
2483 return {Rsrc, OffRes};
2487 case Intrinsic::invariant_start: {
2488 Value *Ptr =
I.getArgOperand(1);
2490 return {
nullptr,
nullptr};
2491 IRB.SetInsertPoint(&
I);
2492 auto [Rsrc,
Off] = getPtrParts(Ptr);
2494 auto *NewRsrc = IRB.CreateIntrinsic(IID, {NewTy}, {
I.getOperand(0), Rsrc});
2495 copyMetadata(NewRsrc, &
I);
2498 I.replaceAllUsesWith(NewRsrc);
2499 return {
nullptr,
nullptr};
2501 case Intrinsic::invariant_end: {
2502 Value *RealPtr =
I.getArgOperand(2);
2504 return {
nullptr,
nullptr};
2505 IRB.SetInsertPoint(&
I);
2506 Value *RealRsrc = getPtrParts(RealPtr).first;
2507 Value *InvPtr =
I.getArgOperand(0);
2509 Value *NewRsrc = IRB.CreateIntrinsic(IID, {RealRsrc->
getType()},
2510 {InvPtr,
Size, RealRsrc});
2511 copyMetadata(NewRsrc, &
I);
2514 I.replaceAllUsesWith(NewRsrc);
2515 return {
nullptr,
nullptr};
2517 case Intrinsic::launder_invariant_group:
2518 case Intrinsic::strip_invariant_group: {
2519 Value *Ptr =
I.getArgOperand(0);
2521 return {
nullptr,
nullptr};
2522 IRB.SetInsertPoint(&
I);
2523 auto [Rsrc,
Off] = getPtrParts(Ptr);
2524 Value *NewRsrc = IRB.CreateIntrinsic(IID, {Rsrc->
getType()}, {Rsrc});
2525 copyMetadata(NewRsrc, &
I);
2528 return {NewRsrc,
Off};
2530 case Intrinsic::amdgcn_load_to_lds:
2531 case Intrinsic::amdgcn_load_async_to_lds: {
2532 Value *Ptr =
I.getArgOperand(0);
2534 return {
nullptr,
nullptr};
2535 IRB.SetInsertPoint(&
I);
2536 auto [Rsrc,
Off] = getPtrParts(Ptr);
2537 Value *LDSPtr =
I.getArgOperand(1);
2538 Value *LoadSize =
I.getArgOperand(2);
2539 Value *ImmOff =
I.getArgOperand(3);
2540 Value *Aux =
I.getArgOperand(4);
2541 Value *SOffset = IRB.getInt32(0);
2543 IID == Intrinsic::amdgcn_load_to_lds
2544 ? Intrinsic::amdgcn_raw_ptr_buffer_load_lds
2545 : Intrinsic::amdgcn_raw_ptr_buffer_load_async_lds;
2546 Instruction *NewLoad = IRB.CreateIntrinsicWithoutFolding(
2547 NewIntr, {}, {Rsrc, LDSPtr, LoadSize,
Off, SOffset, ImmOff, Aux});
2548 copyMetadata(NewLoad, &
I);
2550 I.replaceAllUsesWith(NewLoad);
2551 return {
nullptr,
nullptr};
2554 return {
nullptr,
nullptr};
2557void SplitPtrStructs::processFunction(Function &
F) {
2559 SmallVector<Instruction *, 0> Originals(
2561 LLVM_DEBUG(
dbgs() <<
"Splitting pointer structs in function: " <<
F.getName()
2563 for (Instruction *
I : Originals) {
2571 assert(((Rsrc && Off) || (!Rsrc && !Off)) &&
2572 "Can't have a resource but no offset");
2574 RsrcParts[
I] = Rsrc;
2578 processConditionals();
2579 killAndReplaceSplitInstructions(Originals);
2585 Conditionals.clear();
2586 ConditionalTemps.clear();
2590class AMDGPULowerBufferFatPointers :
public ModulePass {
2594 AMDGPULowerBufferFatPointers() : ModulePass(
ID) {}
2597 bool runOnModule(
Module &M)
override;
2599 void getAnalysisUsage(AnalysisUsage &AU)
const override;
2607 BufferFatPtrToStructTypeMap *TypeMap) {
2608 bool HasFatPointers =
false;
2611 HasFatPointers |= (
I.getType() != TypeMap->remapType(
I.getType()));
2613 for (
const Value *V :
I.operand_values())
2614 HasFatPointers |= (V->getType() != TypeMap->remapType(V->getType()));
2616 return HasFatPointers;
2620 BufferFatPtrToStructTypeMap *TypeMap) {
2621 Type *Ty =
F.getFunctionType();
2622 return Ty != TypeMap->remapType(Ty);
2638 while (!OldF->
empty()) {
2652 CloneMap[&NewArg] = &OldArg;
2653 NewArg.takeName(&OldArg);
2654 Type *OldArgTy = OldArg.getType(), *NewArgTy = NewArg.getType();
2656 NewArg.mutateType(OldArgTy);
2657 OldArg.replaceAllUsesWith(&NewArg);
2658 NewArg.mutateType(NewArgTy);
2662 if (OldArgTy != NewArgTy && !IsIntrinsic)
2665 AttributeFuncs::typeIncompatible(NewArgTy, ArgAttr));
2672 AttributeFuncs::typeIncompatible(NewF->
getReturnType(), RetAttrs));
2674 NewF->
getContext(), OldAttrs.getFnAttrs(), RetAttrs, ArgAttrs));
2682 CloneMap[&BB] = &BB;
2688bool AMDGPULowerBufferFatPointers::run(
Module &M,
const TargetMachine &TM,
2691 const DataLayout &
DL =
M.getDataLayout();
2697 LLVMContext &Ctx =
M.getContext();
2699 BufferFatPtrToStructTypeMap StructTM(
DL);
2700 BufferFatPtrToIntTypeMap IntTM(
DL);
2704 Ctx.
emitError(
"global variables with a buffer fat pointer address "
2705 "space (7) are not supported");
2707 GV.eraseFromParent();
2712 Type *VT = GV.getValueType();
2713 if (VT != StructTM.remapType(VT)) {
2715 Ctx.
emitError(
"global variables that contain buffer fat pointers "
2716 "(address space 7 pointers) are unsupported. Use "
2717 "buffer resource pointers (address space 8) instead");
2719 GV.eraseFromParent();
2728 for (Function &
F :
M.functions())
2735 SmallPtrSet<Constant *, 8> Visited;
2736 SetVector<Constant *> BufferFatPtrConsts;
2737 while (!Worklist.
empty()) {
2739 if (!Visited.
insert(
C).second)
2755 StoreFatPtrsAsIntsAndExpandMemcpyVisitor MemOpsRewrite(&IntTM,
DL,
2757 LegalizeBufferContentTypesVisitor BufferContentsTypeRewrite(
2758 DL,
M.getContext(), &TM);
2759 for (Function &
F :
M.functions()) {
2762 const TargetTransformInfo *
TTI = GetTTI(
F);
2763 ScalarEvolution *SE = GetSE(
F);
2764 Changed |= MemOpsRewrite.processFunction(
F,
TTI, SE);
2765 if (InterfaceChange || BodyChanges) {
2766 NeedsRemap.
push_back(std::make_pair(&
F, InterfaceChange));
2767 Changed |= BufferContentsTypeRewrite.processFunction(
F, SE);
2770 if (NeedsRemap.
empty())
2777 FatPtrConstMaterializer Materializer(&StructTM, CloneMap);
2779 ValueMapper LowerInFuncs(CloneMap,
RF_None, &StructTM, &Materializer);
2780 for (
auto [
F, InterfaceChange] : NeedsRemap) {
2782 if (InterfaceChange)
2788 LowerInFuncs.remapFunction(*NewF);
2793 if (InterfaceChange) {
2794 F->replaceAllUsesWith(NewF);
2795 F->eraseFromParent();
2803 SplitPtrStructs Splitter(
DL,
M.getContext(), &TM);
2804 for (Function *
F : NeedsPostProcess)
2805 Splitter.processFunction(*
F);
2806 for (Function *
F : Intrinsics) {
2810 F->eraseFromParent();
2814 F->replaceAllUsesWith(*NewF);
2820bool AMDGPULowerBufferFatPointers::runOnModule(
Module &M) {
2821 TargetPassConfig &TPC = getAnalysis<TargetPassConfig>();
2822 const TargetMachine &TM = TPC.
getTM<TargetMachine>();
2823 auto GetTTI = [&](
Function &
F) ->
const TargetTransformInfo * {
2824 if (
F.isDeclaration())
2826 return &getAnalysis<TargetTransformInfoWrapperPass>().getTTI(
F);
2828 auto GetSE = [&](
Function &
F) -> ScalarEvolution * {
2829 if (
F.isDeclaration())
2831 return &getAnalysis<ScalarEvolutionWrapperPass>(
F).getSE();
2833 return run(M, TM, GetTTI, GetSE);
2836char AMDGPULowerBufferFatPointers::ID = 0;
2840void AMDGPULowerBufferFatPointers::getAnalysisUsage(
AnalysisUsage &AU)
const {
2846#define PASS_DESC "Lower buffer fat pointer operations to buffer resources"
2857 return new AMDGPULowerBufferFatPointers();
2864 if (
F.isDeclaration())
2869 if (
F.isDeclaration())
2873 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< 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.
static const T * Find(StringRef S, ArrayRef< T > A)
Find KV in array using binary search.
Machine Check Debug Module
static bool processFunction(Function &F, NVPTXTargetMachine &TM)
uint64_t IntrinsicInst * II
OptimizedStructLayoutField Field
#define INITIALIZE_PASS_DEPENDENCY(depName)
#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis)
#define INITIALIZE_PASS_BEGIN(passName, arg, name, cfg, analysis)
const SmallVectorImpl< MachineOperand > & Cond
static void visit(BasicBlock &Start, std::function< bool(BasicBlock *)> op)
This file defines generic set operations that may be used on set's of different types,...
This file defines the SmallVector class.
static SymbolRef::Type getType(const Symbol *Sym)
Target-Independent Code Generator Pass Configuration Options pass.
static APInt getAllOnes(unsigned numBits)
Return an APInt of a specified width with all bits set.
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
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.
LLVM_ABI bool isAllOnesValue() const
Return true if the expression is a constant all-ones value.
LLVM_ABI Type * getType() const
Return the LLVM type of this SCEV expression.
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 const SCEV * getTruncateOrNoop(const SCEV *V, Type *Ty)
Return a SCEV corresponding to a conversion of the input value to the specified type.
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.
This class represents the LLVM 'select' instruction.
ArrayRef< value_type > getArrayRef() const
bool insert(const value_type &X)
Insert a new element into the SetVector.
This instruction constructs a fixed permutation of two input vectors.
A templated base class for SmallPtrSet which provides the typesafe interface that is common across al...
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
An instruction for storing to memory.
Value * getValueOperand()
Value * getPointerOperand()
MutableArrayRef< TypeSize > getMemberOffsets()
static LLVM_ABI StructType * get(LLVMContext &Context, ArrayRef< Type * > Elements, bool isPacked=false)
This static method is the primary way to create a literal StructType.
static LLVM_ABI StructType * create(LLVMContext &Context, StringRef Name)
This creates an identified struct.
bool isLiteral() const
Return true if this type is uniqued by structural equivalence, false if it is a struct definition.
Type * getElementType(unsigned N) const
Analysis pass providing the TargetTransformInfo.
Primary interface to the complete machine description for the target machine.
const STC & getSubtarget(const Function &F) const
This method returns a pointer to the specified type of TargetSubtargetInfo.
Target-Independent Code Generator Pass Configuration Options.
TMC & getTM() const
Get the right type of TargetMachine for this target.
The instances of the Type class are immutable: once they are created, they are never changed.
LLVM_ABI unsigned getIntegerBitWidth() const
bool isVectorTy() const
True if this is an instance of VectorType.
Type * getArrayElementType() const
ArrayRef< Type * > subtypes() const
bool isSingleValueType() const
Return true if the type is a valid type for a register in codegen.
unsigned getNumContainedTypes() const
Return the number of types in the derived type.
Type * getScalarType() const
If this is a vector type, return the element type, otherwise return 'this'.
LLVM_ABI Type * getWithNewBitWidth(unsigned NewBitWidth) const
Given an integer or vector type, change the lane bitwidth to NewBitwidth, whilst keeping the old numb...
LLVM_ABI Type * getWithNewType(Type *EltTy) const
Given vector type, change the element type, whilst keeping the old number of elements.
LLVMContext & getContext() const
Return the LLVMContext in which this type was uniqued.
LLVM_ABI unsigned getScalarSizeInBits() const LLVM_READONLY
If this is a vector type, return the getPrimitiveSizeInBits value for the element type.
bool isIntegerTy() const
True if this is an instance of IntegerType.
Type * getContainedType(unsigned i) const
This method is used to implement the type iterator (defined at the end of the file).
static LLVM_ABI UndefValue * get(Type *T)
Static factory methods - Return an 'undef' object of the specified type.
A Use represents the edge between a Value definition and its users.
void setOperand(unsigned i, Value *Val)
Value * getOperand(unsigned i) const
This is a class that can be implemented by clients to remap types when cloning constants and instruct...
size_type count(const KeyT &Val) const
Return 1 if the specified key is in the map, 0 otherwise.
iterator find(const KeyT &Val)
std::pair< iterator, bool > insert(const std::pair< KeyT, ValueT > &KV)
ValueMapIteratorImpl< MapT, const Value *, false > iterator
LLVM_ABI Constant * mapConstant(const Constant &C)
LLVM_ABI Value * mapValue(const Value &V)
LLVM Value Representation.
Type * getType() const
All values are typed, get the type of this value.
LLVM_ABI void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
LLVMContext & getContext() const
All values hold a context through their type.
LLVM_ABI StringRef getName() const
Return a constant reference to the value's name.
LLVM_ABI void takeName(Value *V)
Transfer the name from V to this value.
std::pair< iterator, bool > insert(const ValueT &V)
bool contains(const_arg_type_t< ValueT > V) const
Check if the set contains the given element.
constexpr bool isKnownMultipleOf(ScalarTy RHS) const
This function tells the caller whether the element count is known at compile time to be a multiple of...
constexpr ScalarTy getFixedValue() const
constexpr ScalarTy getKnownMinValue() const
Returns the minimum value this quantity can represent.
An efficient, type-erasing, non-owning reference to a callable.
self_iterator getIterator()
iterator insertAfter(iterator where, pointer New)
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
@ BUFFER_FAT_POINTER
Address space for 160-bit buffer fat pointers.
@ BUFFER_RESOURCE
Address space for 128-bit buffer resources.
constexpr char Align[]
Key for Kernel::Arg::Metadata::mAlign.
constexpr char Args[]
Key for Kernel::Metadata::mArgs.
constexpr std::underlying_type_t< E > Mask()
Get a bitmask with 1s in all places up to the high-order bit of E's largest value.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
@ C
The default llvm calling convention, compatible with C.
LLVM_ABI std::optional< Function * > remangleIntrinsicFunction(Function *F)
bool match(Val *V, const Pattern &P)
is_zero m_Zero()
Match any null constant or a vector with all elements equal to 0.
SmallVector< DbgVariableRecord * > getDVRAssignmentMarkers(const Instruction *Inst)
Return a range of dbg_assign records for which Inst performs the assignment they encode.
DXILDebugInfoMap run(Module &M)
friend class Instruction
Iterator for Instructions in a `BasicBlock.
This is an optimization pass for GlobalISel generic memory operations.
detail::zippy< detail::zip_shortest, T, U, Args... > zip(T &&t, U &&u, Args &&...args)
zip iterator for two or more iteratable types.
LLVM_ABI void findDbgValues(Value *V, SmallVectorImpl< DbgVariableRecord * > &DbgVariableRecords)
Finds the dbg.values describing a value.
ModulePass * createAMDGPULowerBufferFatPointersPass()
auto enumerate(FirstRange &&First, RestRanges &&...Rest)
Given two or more input ranges, returns a new range whose values are tuples (A, B,...
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
LLVM_ABI void copyMetadataForLoad(LoadInst &Dest, const LoadInst &Source)
Copy the metadata from the source instruction to the destination (the replacement for the source inst...
bool set_is_subset(const S1Ty &S1, const S2Ty &S2)
set_is_subset(A, B) - Return true iff A in B
iterator_range< early_inc_iterator_impl< detail::IterOfRange< RangeT > > > make_early_inc_range(RangeT &&Range)
Make a range that does early increment to allow mutation of the underlying range without disrupting i...
InnerAnalysisManagerProxy< FunctionAnalysisManager, Module > FunctionAnalysisManagerModuleProxy
Provide the FunctionAnalysisManager to Module proxy.
constexpr bool isPowerOf2_64(uint64_t Value)
Return true if the argument is a power of two > 0 (64 bit edition.)
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Value
auto dyn_cast_or_null(const Y &Val)
LLVM_ABI bool convertUsersOfConstantsToInstructions(ArrayRef< Constant * > Consts, Function *RestrictToFunc=nullptr, bool RemoveDeadConstants=true, bool IncludeSelf=false)
Replace constant expressions users of the given constants with instructions.
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
LLVM_ABI Value * emitGEPOffset(IRBuilderBase *Builder, const DataLayout &DL, User *GEP, bool NoAssumptions=false)
Given a getelementptr instruction/constantexpr, emit the code necessary to compute the offset from th...
constexpr bool isPowerOf2_32(uint32_t Value)
Return true if the argument is a power of two > 0.
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
SmallVector< ValueTypeFromRangeType< R >, Size > to_vector(R &&Range)
Given a range of type R, iterate the entire range and return a SmallVector with elements of the vecto...
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
char & AMDGPULowerBufferFatPointersID
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
MutableArrayRef(T &OneElt) -> MutableArrayRef< T >
AtomicOrdering
Atomic ordering for LLVM's memory model.
constexpr T divideCeil(U Numerator, V Denominator)
Returns the integer ceil(Numerator / Denominator).
IRBuilder(LLVMContext &, FolderTy, InserterTy, MDNode *, ArrayRef< OperandBundleDef >) -> IRBuilder< FolderTy, InserterTy >
DWARFExpression::Operation Op
S1Ty set_difference(const S1Ty &S1, const S2Ty &S2)
set_difference(A, B) - Return A - B
ArrayRef(const T &OneElt) -> ArrayRef< T >
ValueMap< const Value *, WeakTrackingVH > ValueToValueMapTy
LLVM_ABI void expandMemSetAsLoop(MemSetInst *MemSet, const TargetTransformInfo *TTI=nullptr)
Expand MemSet as a loop.
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
LLVM_ABI void expandMemSetPatternAsLoop(MemSetPatternInst *MemSet, const TargetTransformInfo *TTI=nullptr)
Expand MemSetPattern as a loop.
iterator_range< pointer_iterator< WrappedIteratorT > > make_pointer_range(RangeT &&Range)
Align commonAlignment(Align A, uint64_t Offset)
Returns the alignment that satisfies both alignments.
LLVM_ABI void expandMemCpyAsLoop(MemCpyInst *MemCpy, const TargetTransformInfo &TTI, ScalarEvolution *SE=nullptr)
Expand MemCpy as a loop. MemCpy is not deleted.
AnalysisManager< Module > ModuleAnalysisManager
Convenience typedef for the Module analysis manager.
LLVM_ABI void reportFatalUsageError(Error Err)
Report a fatal error that does not indicate a bug in LLVM.
LLVM_ABI AAMDNodes adjustForAccess(unsigned AccessSize)
Create a new AAMDNode for accessing AccessSize bytes of this AAMDNode.
PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM)
This struct is a compact representation of a valid (non-zero power of two) alignment.