241#include "llvm/IR/IntrinsicsAMDGPU.h"
259#define DEBUG_TYPE "amdgpu-lower-buffer-fat-pointers"
281 Type *remapType(
Type *SrcTy)
override;
282 void clear() { Map.clear(); }
288class BufferFatPtrToIntTypeMap :
public BufferFatPtrTypeLoweringBase {
289 using BufferFatPtrTypeLoweringBase::BufferFatPtrTypeLoweringBase;
299class BufferFatPtrToStructTypeMap :
public BufferFatPtrTypeLoweringBase {
300 using BufferFatPtrTypeLoweringBase::BufferFatPtrTypeLoweringBase;
309Type *BufferFatPtrTypeLoweringBase::remapTypeImpl(
Type *Ty) {
315 return *
Entry = remapScalar(PT);
321 return *
Entry = remapVector(VT);
329 bool IsUniqued = !TyAsStruct || TyAsStruct->
isLiteral();
338 Type *NewElem = remapTypeImpl(OldElem);
339 ElementTypes[
I] = NewElem;
340 Changed |= (OldElem != NewElem);
348 return *
Entry = ArrayType::get(ElementTypes[0], ArrTy->getNumElements());
350 return *
Entry = FunctionType::get(ElementTypes[0],
360 SmallString<16>
Name(STy->getName());
368Type *BufferFatPtrTypeLoweringBase::remapType(
Type *SrcTy) {
369 return remapTypeImpl(SrcTy);
372Type *BufferFatPtrToStructTypeMap::remapScalar(PointerType *PT) {
373 LLVMContext &Ctx = PT->getContext();
378Type *BufferFatPtrToStructTypeMap::remapVector(VectorType *VT) {
379 ElementCount
EC = VT->getElementCount();
380 LLVMContext &Ctx = VT->getContext();
399 if (!ST->isLiteral() || ST->getNumElements() != 2)
405 return MaybeRsrc && MaybeOff &&
414 return isBufferFatPtrOrVector(U.get()->getType());
427class StoreFatPtrsAsIntsAndExpandMemcpyVisitor
428 :
public InstVisitor<StoreFatPtrsAsIntsAndExpandMemcpyVisitor, bool> {
429 BufferFatPtrToIntTypeMap *TypeMap;
435 const TargetMachine *TM;
446 StoreFatPtrsAsIntsAndExpandMemcpyVisitor(BufferFatPtrToIntTypeMap *TypeMap,
447 const DataLayout &
DL,
449 const TargetMachine *TM)
450 : TypeMap(TypeMap), IRB(Ctx, InstSimplifyFolder(
DL)), TM(TM) {}
453 bool visitInstruction(Instruction &
I) {
return false; }
454 bool visitAllocaInst(AllocaInst &
I);
455 bool visitLoadInst(LoadInst &LI);
456 bool visitStoreInst(StoreInst &SI);
457 bool visitGetElementPtrInst(GetElementPtrInst &
I);
459 bool visitMemCpyInst(MemCpyInst &MCI);
460 bool visitMemMoveInst(MemMoveInst &MMI);
461 bool visitMemSetInst(MemSetInst &MSI);
462 bool visitMemSetPatternInst(MemSetPatternInst &MSPI);
466Value *StoreFatPtrsAsIntsAndExpandMemcpyVisitor::fatPtrsToInts(
471 if (
Find != ConvertedForStore.
end())
474 Value *Cast = IRB.CreatePtrToInt(V, To, Name +
".int");
475 ConvertedForStore[
V] = Cast;
483 Type *FromPart = AT->getArrayElementType();
485 for (uint64_t
I = 0,
E = AT->getArrayNumElements();
I <
E; ++
I) {
488 fatPtrsToInts(
Field, FromPart, ToPart, Name +
"." + Twine(
I));
489 Ret = IRB.CreateInsertValue(Ret, NewField,
I);
492 for (
auto [Idx, FromPart, ToPart] :
494 Value *
Field = IRB.CreateExtractValue(V, Idx);
496 fatPtrsToInts(
Field, FromPart, ToPart, Name +
"." + Twine(Idx));
497 Ret = IRB.CreateInsertValue(Ret, NewField, Idx);
500 ConvertedForStore[
V] = Ret;
504Value *StoreFatPtrsAsIntsAndExpandMemcpyVisitor::intsToFatPtrs(
509 Value *Cast = IRB.CreateIntToPtr(V, To, Name +
".ptr");
519 for (uint64_t
I = 0,
E = AT->getArrayNumElements();
I <
E; ++
I) {
522 intsToFatPtrs(
Field, FromPart, ToPart, Name +
"." + Twine(
I));
523 Ret = IRB.CreateInsertValue(Ret, NewField,
I);
526 for (
auto [Idx, FromPart, ToPart] :
528 Value *
Field = IRB.CreateExtractValue(V, Idx);
530 intsToFatPtrs(
Field, FromPart, ToPart, Name +
"." + Twine(Idx));
531 Ret = IRB.CreateInsertValue(Ret, NewField, Idx);
537bool StoreFatPtrsAsIntsAndExpandMemcpyVisitor::processFunction(Function &
F) {
551 ConvertedForStore.
clear();
555bool StoreFatPtrsAsIntsAndExpandMemcpyVisitor::visitAllocaInst(AllocaInst &
I) {
556 Type *Ty =
I.getAllocatedType();
557 Type *NewTy = TypeMap->remapType(Ty);
560 I.setAllocatedType(NewTy);
564bool StoreFatPtrsAsIntsAndExpandMemcpyVisitor::visitGetElementPtrInst(
565 GetElementPtrInst &
I) {
566 Type *Ty =
I.getSourceElementType();
567 Type *NewTy = TypeMap->remapType(Ty);
572 I.setSourceElementType(NewTy);
573 I.setResultElementType(TypeMap->remapType(
I.getResultElementType()));
577bool StoreFatPtrsAsIntsAndExpandMemcpyVisitor::visitLoadInst(LoadInst &LI) {
579 Type *IntTy = TypeMap->remapType(Ty);
583 IRB.SetInsertPoint(&LI);
585 NLI->mutateType(IntTy);
586 NLI = IRB.Insert(NLI);
589 Value *CastBack = intsToFatPtrs(NLI, IntTy, Ty, NLI->getName());
595bool StoreFatPtrsAsIntsAndExpandMemcpyVisitor::visitStoreInst(StoreInst &SI) {
597 Type *Ty =
V->getType();
598 Type *IntTy = TypeMap->remapType(Ty);
602 IRB.SetInsertPoint(&SI);
603 Value *IntV = fatPtrsToInts(V, Ty, IntTy,
V->getName());
607 SI.setOperand(0, IntV);
611bool StoreFatPtrsAsIntsAndExpandMemcpyVisitor::visitMemCpyInst(
624bool StoreFatPtrsAsIntsAndExpandMemcpyVisitor::visitMemMoveInst(
630 "memmove() on buffer descriptors is not implemented because pointer "
631 "comparison on buffer descriptors isn't implemented\n");
634bool StoreFatPtrsAsIntsAndExpandMemcpyVisitor::visitMemSetInst(
644bool StoreFatPtrsAsIntsAndExpandMemcpyVisitor::visitMemSetPatternInst(
645 MemSetPatternInst &MSPI) {
669class LegalizeBufferContentTypesVisitor
670 :
public InstVisitor<LegalizeBufferContentTypesVisitor, bool> {
671 friend class InstVisitor<LegalizeBufferContentTypesVisitor, bool>;
675 const DataLayout &
DL;
679 Type *scalarArrayTypeAsVector(
Type *MaybeArrayType);
680 Value *arrayToVector(
Value *V,
Type *TargetType,
const Twine &Name);
681 Value *vectorToArray(
Value *V,
Type *OrigType,
const Twine &Name);
689 Value *makeLegalNonAggregate(
Value *V,
Type *TargetType,
const Twine &Name);
690 Value *makeIllegalNonAggregate(
Value *V,
Type *OrigType,
const Twine &Name);
703 void getVecSlices(
Type *
T, SmallVectorImpl<VecSlice> &Slices);
705 Value *extractSlice(
Value *Vec, VecSlice S,
const Twine &Name);
706 Value *insertSlice(
Value *Whole,
Value *Part, VecSlice S,
const Twine &Name);
716 Type *intrinsicTypeFor(
Type *LegalType);
718 bool visitLoadImpl(LoadInst &OrigLI,
Type *PartType,
719 SmallVectorImpl<uint32_t> &AggIdxs, uint64_t AggByteOffset,
720 Value *&Result,
const Twine &Name);
722 std::pair<bool, bool> visitStoreImpl(StoreInst &OrigSI,
Type *PartType,
723 SmallVectorImpl<uint32_t> &AggIdxs,
724 uint64_t AggByteOffset,
727 bool visitInstruction(Instruction &
I) {
return false; }
728 bool visitLoadInst(LoadInst &LI);
729 bool visitStoreInst(StoreInst &SI);
732 LegalizeBufferContentTypesVisitor(
const DataLayout &
DL, LLVMContext &Ctx)
733 : IRB(Ctx, InstSimplifyFolder(
DL)),
DL(
DL) {}
738Type *LegalizeBufferContentTypesVisitor::scalarArrayTypeAsVector(
Type *
T) {
742 Type *ET = AT->getElementType();
745 "should have recursed");
746 if (!
DL.typeSizeEqualsStoreSize(AT))
748 "loading padded arrays from buffer fat pinters should have recursed");
752Value *LegalizeBufferContentTypesVisitor::arrayToVector(
Value *V,
757 unsigned EC = VT->getNumElements();
758 for (
auto I : iota_range<unsigned>(0, EC,
false)) {
759 Value *Elem = IRB.CreateExtractValue(V,
I, Name +
".elem." + Twine(
I));
760 VectorRes = IRB.CreateInsertElement(VectorRes, Elem,
I,
761 Name +
".as.vec." + Twine(
I));
766Value *LegalizeBufferContentTypesVisitor::vectorToArray(
Value *V,
771 unsigned EC = AT->getNumElements();
772 for (
auto I : iota_range<unsigned>(0, EC,
false)) {
773 Value *Elem = IRB.CreateExtractElement(V,
I, Name +
".elem." + Twine(
I));
774 ArrayRes = IRB.CreateInsertValue(ArrayRes, Elem,
I,
775 Name +
".as.array." + Twine(
I));
780Type *LegalizeBufferContentTypesVisitor::legalNonAggregateFor(
Type *
T) {
781 TypeSize
Size =
DL.getTypeStoreSizeInBits(
T);
783 if (!
DL.typeSizeEqualsStoreSize(
T))
784 T = IRB.getIntNTy(
Size.getFixedValue());
785 Type *ElemTy =
T->getScalarType();
791 unsigned ElemSize =
DL.getTypeSizeInBits(ElemTy).getFixedValue();
792 if (
isPowerOf2_32(ElemSize) && ElemSize >= 16 && ElemSize <= 128) {
797 Type *BestVectorElemType =
nullptr;
798 if (
Size.isKnownMultipleOf(32))
799 BestVectorElemType = IRB.getInt32Ty();
800 else if (
Size.isKnownMultipleOf(16))
801 BestVectorElemType = IRB.getInt16Ty();
803 BestVectorElemType = IRB.getInt8Ty();
804 unsigned NumCastElems =
806 if (NumCastElems == 1)
807 return BestVectorElemType;
811Value *LegalizeBufferContentTypesVisitor::makeLegalNonAggregate(
812 Value *V,
Type *TargetType,
const Twine &Name) {
813 Type *SourceType =
V->getType();
814 TypeSize SourceSize =
DL.getTypeSizeInBits(SourceType);
815 TypeSize TargetSize =
DL.getTypeSizeInBits(TargetType);
816 if (SourceSize != TargetSize) {
819 Value *AsScalar = IRB.CreateBitCast(V, ShortScalarTy, Name +
".as.scalar");
820 Value *Zext = IRB.CreateZExt(AsScalar, ByteScalarTy, Name +
".zext");
822 SourceType = ByteScalarTy;
824 return IRB.CreateBitCast(V, TargetType, Name +
".legal");
827Value *LegalizeBufferContentTypesVisitor::makeIllegalNonAggregate(
828 Value *V,
Type *OrigType,
const Twine &Name) {
829 Type *LegalType =
V->getType();
830 TypeSize LegalSize =
DL.getTypeSizeInBits(LegalType);
831 TypeSize OrigSize =
DL.getTypeSizeInBits(OrigType);
832 if (LegalSize != OrigSize) {
835 Value *AsScalar = IRB.CreateBitCast(V, ByteScalarTy, Name +
".bytes.cast");
836 Value *Trunc = IRB.CreateTrunc(AsScalar, ShortScalarTy, Name +
".trunc");
837 return IRB.CreateBitCast(Trunc, OrigType, Name +
".orig");
839 return IRB.CreateBitCast(V, OrigType, Name +
".real.ty");
842Type *LegalizeBufferContentTypesVisitor::intrinsicTypeFor(
Type *LegalType) {
846 Type *ET = VT->getElementType();
849 if (VT->getNumElements() == 1)
851 if (
DL.getTypeSizeInBits(LegalType) == 96 &&
DL.getTypeSizeInBits(ET) < 32)
854 switch (VT->getNumElements()) {
858 return IRB.getInt8Ty();
860 return IRB.getInt16Ty();
862 return IRB.getInt32Ty();
872void LegalizeBufferContentTypesVisitor::getVecSlices(
873 Type *
T, SmallVectorImpl<VecSlice> &Slices) {
879 uint64_t ElemBitWidth =
880 DL.getTypeSizeInBits(VT->getElementType()).getFixedValue();
882 uint64_t ElemsPer4Words = 128 / ElemBitWidth;
883 uint64_t ElemsPer2Words = ElemsPer4Words / 2;
884 uint64_t ElemsPerWord = ElemsPer2Words / 2;
885 uint64_t ElemsPerShort = ElemsPerWord / 2;
886 uint64_t ElemsPerByte = ElemsPerShort / 2;
890 uint64_t ElemsPer3Words = ElemsPerWord * 3;
892 uint64_t TotalElems = VT->getNumElements();
894 auto TrySlice = [&](
unsigned MaybeLen) {
895 if (MaybeLen > 0 && Index + MaybeLen <= TotalElems) {
896 VecSlice Slice{
Index, MaybeLen};
903 while (Index < TotalElems) {
904 TrySlice(ElemsPer4Words) || TrySlice(ElemsPer3Words) ||
905 TrySlice(ElemsPer2Words) || TrySlice(ElemsPerWord) ||
906 TrySlice(ElemsPerShort) || TrySlice(ElemsPerByte);
910Value *LegalizeBufferContentTypesVisitor::extractSlice(
Value *Vec, VecSlice S,
915 if (S.Length == VecVT->getNumElements() && S.Index == 0)
918 return IRB.CreateExtractElement(Vec, S.Index,
919 Name +
".slice." + Twine(S.Index));
921 llvm::iota_range<int>(S.Index, S.Index + S.Length,
false));
922 return IRB.CreateShuffleVector(Vec, Mask, Name +
".slice." + Twine(S.Index));
925Value *LegalizeBufferContentTypesVisitor::insertSlice(
Value *Whole,
Value *Part,
931 if (S.Length == WholeVT->getNumElements() && S.Index == 0)
934 return IRB.CreateInsertElement(Whole, Part, S.Index,
935 Name +
".slice." + Twine(S.Index));
940 SmallVector<int> ExtPartMask(NumElems, -1);
945 Value *ExtPart = IRB.CreateShuffleVector(Part, ExtPartMask,
946 Name +
".ext." + Twine(S.Index));
948 SmallVector<int>
Mask =
953 return IRB.CreateShuffleVector(Whole, ExtPart, Mask,
954 Name +
".parts." + Twine(S.Index));
957bool LegalizeBufferContentTypesVisitor::visitLoadImpl(
958 LoadInst &OrigLI,
Type *PartType, SmallVectorImpl<uint32_t> &AggIdxs,
959 uint64_t AggByteOff,
Value *&Result,
const Twine &Name) {
961 const StructLayout *Layout =
DL.getStructLayout(ST);
963 for (
auto [
I, ElemTy,
Offset] :
966 Changed |= visitLoadImpl(OrigLI, ElemTy, AggIdxs,
967 AggByteOff +
Offset.getFixedValue(), Result,
968 Name +
"." + Twine(
I));
974 Type *ElemTy = AT->getElementType();
977 TypeSize ElemStoreSize =
DL.getTypeStoreSize(ElemTy);
979 for (
auto I : llvm::iota_range<uint32_t>(0, AT->getNumElements(),
982 Changed |= visitLoadImpl(OrigLI, ElemTy, AggIdxs,
984 Result, Name + Twine(
I));
993 Type *ArrayAsVecType = scalarArrayTypeAsVector(PartType);
994 Type *LegalType = legalNonAggregateFor(ArrayAsVecType);
997 getVecSlices(LegalType, Slices);
998 bool HasSlices = Slices.
size() > 1;
999 bool IsAggPart = !AggIdxs.
empty();
1001 if (!HasSlices && !IsAggPart) {
1002 Type *LoadableType = intrinsicTypeFor(LegalType);
1003 if (LoadableType == PartType)
1006 IRB.SetInsertPoint(&OrigLI);
1008 NLI->mutateType(LoadableType);
1009 NLI = IRB.Insert(NLI);
1010 NLI->setName(Name +
".loadable");
1012 LoadsRes = IRB.CreateBitCast(NLI, LegalType, Name +
".from.loadable");
1014 IRB.SetInsertPoint(&OrigLI);
1022 unsigned ElemBytes =
DL.getTypeStoreSize(ElemType);
1024 if (IsAggPart && Slices.
empty())
1026 for (VecSlice S : Slices) {
1029 int64_t ByteOffset = AggByteOff + S.Index * ElemBytes;
1031 Value *NewPtr = IRB.CreateGEP(
1033 OrigPtr->
getName() +
".off.ptr." + Twine(ByteOffset),
1035 Type *LoadableType = intrinsicTypeFor(SliceType);
1036 LoadInst *NewLI = IRB.CreateAlignedLoad(
1038 Name +
".off." + Twine(ByteOffset));
1044 Value *
Loaded = IRB.CreateBitCast(NewLI, SliceType,
1045 NewLI->
getName() +
".from.loadable");
1046 LoadsRes = insertSlice(LoadsRes, Loaded, S, Name);
1049 if (LegalType != ArrayAsVecType)
1050 LoadsRes = makeIllegalNonAggregate(LoadsRes, ArrayAsVecType, Name);
1051 if (ArrayAsVecType != PartType)
1052 LoadsRes = vectorToArray(LoadsRes, PartType, Name);
1055 Result = IRB.CreateInsertValue(Result, LoadsRes, AggIdxs, Name);
1061bool LegalizeBufferContentTypesVisitor::visitLoadInst(LoadInst &LI) {
1065 SmallVector<uint32_t> AggIdxs;
1068 bool Changed = visitLoadImpl(LI, OrigType, AggIdxs, 0, Result, LI.
getName());
1077std::pair<bool, bool> LegalizeBufferContentTypesVisitor::visitStoreImpl(
1078 StoreInst &OrigSI,
Type *PartType, SmallVectorImpl<uint32_t> &AggIdxs,
1079 uint64_t AggByteOff,
const Twine &Name) {
1081 const StructLayout *Layout =
DL.getStructLayout(ST);
1083 for (
auto [
I, ElemTy,
Offset] :
1086 Changed |= std::get<0>(visitStoreImpl(OrigSI, ElemTy, AggIdxs,
1087 AggByteOff +
Offset.getFixedValue(),
1088 Name +
"." + Twine(
I)));
1091 return std::make_pair(
Changed,
false);
1094 Type *ElemTy = AT->getElementType();
1097 TypeSize ElemStoreSize =
DL.getTypeStoreSize(ElemTy);
1099 for (
auto I : llvm::iota_range<uint32_t>(0, AT->getNumElements(),
1102 Changed |= std::get<0>(visitStoreImpl(
1103 OrigSI, ElemTy, AggIdxs,
1107 return std::make_pair(
Changed,
false);
1112 Value *NewData = OrigData;
1114 bool IsAggPart = !AggIdxs.
empty();
1116 NewData = IRB.CreateExtractValue(NewData, AggIdxs, Name);
1118 Type *ArrayAsVecType = scalarArrayTypeAsVector(PartType);
1119 if (ArrayAsVecType != PartType) {
1120 NewData = arrayToVector(NewData, ArrayAsVecType, Name);
1123 Type *LegalType = legalNonAggregateFor(ArrayAsVecType);
1124 if (LegalType != ArrayAsVecType) {
1125 NewData = makeLegalNonAggregate(NewData, LegalType, Name);
1129 getVecSlices(LegalType, Slices);
1130 bool NeedToSplit = Slices.
size() > 1 || IsAggPart;
1132 Type *StorableType = intrinsicTypeFor(LegalType);
1133 if (StorableType == PartType)
1134 return std::make_pair(
false,
false);
1135 NewData = IRB.CreateBitCast(NewData, StorableType, Name +
".storable");
1137 return std::make_pair(
true,
true);
1142 if (IsAggPart && Slices.
empty())
1144 unsigned ElemBytes =
DL.getTypeStoreSize(ElemType);
1146 for (VecSlice S : Slices) {
1149 int64_t ByteOffset = AggByteOff + S.Index * ElemBytes;
1151 IRB.CreateGEP(IRB.getInt8Ty(), OrigPtr, IRB.getInt32(ByteOffset),
1152 OrigPtr->
getName() +
".part." + Twine(S.Index),
1154 Value *DataSlice = extractSlice(NewData, S, Name);
1155 Type *StorableType = intrinsicTypeFor(SliceType);
1156 DataSlice = IRB.CreateBitCast(DataSlice, StorableType,
1157 DataSlice->
getName() +
".storable");
1161 NewSI->setOperand(0, DataSlice);
1162 NewSI->setOperand(1, NewPtr);
1165 return std::make_pair(
true,
false);
1168bool LegalizeBufferContentTypesVisitor::visitStoreInst(StoreInst &SI) {
1171 IRB.SetInsertPoint(&SI);
1172 SmallVector<uint32_t> AggIdxs;
1173 Value *OrigData =
SI.getValueOperand();
1174 auto [
Changed, ModifiedInPlace] =
1175 visitStoreImpl(SI, OrigData->
getType(), AggIdxs, 0, OrigData->
getName());
1176 if (
Changed && !ModifiedInPlace)
1177 SI.eraseFromParent();
1181bool LegalizeBufferContentTypesVisitor::processFunction(Function &
F) {
1192static std::pair<Constant *, Constant *>
1195 return std::make_pair(
C->getAggregateElement(0u),
C->getAggregateElement(1u));
1200class FatPtrConstMaterializer final :
public ValueMaterializer {
1201 BufferFatPtrToStructTypeMap *TypeMap;
1207 ValueMapper InternalMapper;
1209 Constant *materializeBufferFatPtrConst(Constant *
C);
1213 FatPtrConstMaterializer(BufferFatPtrToStructTypeMap *TypeMap,
1216 InternalMapper(UnderlyingMap,
RF_None, TypeMap, this) {}
1217 ~FatPtrConstMaterializer() =
default;
1223Constant *FatPtrConstMaterializer::materializeBufferFatPtrConst(Constant *
C) {
1224 Type *SrcTy =
C->getType();
1226 if (
C->isNullValue())
1227 return ConstantAggregateZero::getNullValue(NewTy);
1240 if (Constant *S =
VC->getSplatValue()) {
1245 auto EC =
VC->getType()->getElementCount();
1251 for (
Value *
Op :
VC->operand_values()) {
1266 "fat pointer) values are not supported");
1270 "constant exprs containing ptr addrspace(7) (buffer "
1271 "fat pointer) values should have been expanded earlier");
1276Value *FatPtrConstMaterializer::materialize(
Value *V) {
1284 return materializeBufferFatPtrConst(
C);
1292class SplitPtrStructs :
public InstVisitor<SplitPtrStructs, PtrParts> {
1335 void processConditionals();
1385void SplitPtrStructs::copyMetadata(
Value *Dest,
Value *Src) {
1389 if (!DestI || !SrcI)
1392 DestI->copyMetadata(*SrcI);
1397 "of something that wasn't rewritten");
1398 auto *RsrcEntry = &RsrcParts[
V];
1399 auto *OffEntry = &OffParts[
V];
1400 if (*RsrcEntry && *OffEntry)
1401 return {*RsrcEntry, *OffEntry};
1405 return {*RsrcEntry = Rsrc, *OffEntry =
Off};
1408 IRBuilder<InstSimplifyFolder>::InsertPointGuard Guard(IRB);
1413 return {*RsrcEntry = Rsrc, *OffEntry =
Off};
1416 IRB.SetInsertPoint(*
I->getInsertionPointAfterDef());
1417 IRB.SetCurrentDebugLocation(
I->getDebugLoc());
1419 IRB.SetInsertPointPastAllocas(
A->getParent());
1420 IRB.SetCurrentDebugLocation(
DebugLoc());
1422 Value *Rsrc = IRB.CreateExtractValue(V, 0,
V->getName() +
".rsrc");
1423 Value *
Off = IRB.CreateExtractValue(V, 1,
V->getName() +
".off");
1424 return {*RsrcEntry = Rsrc, *OffEntry =
Off};
1437 V =
GEP->getPointerOperand();
1439 V = ASC->getPointerOperand();
1443void SplitPtrStructs::getPossibleRsrcRoots(Instruction *
I,
1444 SmallPtrSetImpl<Value *> &Roots,
1445 SmallPtrSetImpl<Value *> &Seen) {
1449 for (
Value *In :
PHI->incoming_values()) {
1456 if (!Seen.
insert(SI).second)
1471void SplitPtrStructs::processConditionals() {
1472 SmallDenseMap<Value *, Value *> FoundRsrcs;
1473 SmallPtrSet<Value *, 4> Roots;
1474 SmallPtrSet<Value *, 4> Seen;
1475 for (Instruction *
I : Conditionals) {
1477 Value *Rsrc = RsrcParts[
I];
1479 assert(Rsrc && Off &&
"must have visited conditionals by now");
1481 std::optional<Value *> MaybeRsrc;
1482 auto MaybeFoundRsrc = FoundRsrcs.
find(
I);
1483 if (MaybeFoundRsrc != FoundRsrcs.
end()) {
1484 MaybeRsrc = MaybeFoundRsrc->second;
1486 IRBuilder<InstSimplifyFolder>::InsertPointGuard Guard(IRB);
1489 getPossibleRsrcRoots(
I, Roots, Seen);
1492 for (
Value *V : Roots)
1494 for (
Value *V : Seen)
1506 if (Diff.size() == 1) {
1507 Value *RootVal = *Diff.begin();
1511 MaybeRsrc = std::get<0>(getPtrParts(RootVal));
1513 MaybeRsrc = RootVal;
1521 IRB.SetInsertPoint(*
PHI->getInsertionPointAfterDef());
1522 IRB.SetCurrentDebugLocation(
PHI->getDebugLoc());
1524 NewRsrc = *MaybeRsrc;
1527 auto *RsrcPHI = IRB.CreatePHI(RsrcTy,
PHI->getNumIncomingValues());
1528 RsrcPHI->takeName(Rsrc);
1529 for (
auto [V, BB] :
llvm::zip(
PHI->incoming_values(),
PHI->blocks())) {
1530 Value *VRsrc = std::get<0>(getPtrParts(V));
1531 RsrcPHI->addIncoming(VRsrc, BB);
1533 copyMetadata(RsrcPHI,
PHI);
1538 auto *NewOff = IRB.CreatePHI(OffTy,
PHI->getNumIncomingValues());
1539 NewOff->takeName(Off);
1540 for (
auto [V, BB] :
llvm::zip(
PHI->incoming_values(),
PHI->blocks())) {
1541 assert(OffParts.
count(V) &&
"An offset part had to be created by now");
1542 Value *VOff = std::get<1>(getPtrParts(V));
1543 NewOff->addIncoming(VOff, BB);
1545 copyMetadata(NewOff,
PHI);
1554 ConditionalTemps.push_back(RsrcInst);
1555 RsrcInst->replaceAllUsesWith(NewRsrc);
1558 ConditionalTemps.push_back(OffInst);
1559 OffInst->replaceAllUsesWith(NewOff);
1564 for (
Value *V : Seen)
1565 FoundRsrcs[
V] = NewRsrc;
1570 if (RsrcInst != *MaybeRsrc) {
1571 ConditionalTemps.push_back(RsrcInst);
1572 RsrcInst->replaceAllUsesWith(*MaybeRsrc);
1575 for (
Value *V : Seen)
1576 FoundRsrcs[
V] = *MaybeRsrc;
1584void SplitPtrStructs::killAndReplaceSplitInstructions(
1585 SmallVectorImpl<Instruction *> &Origs) {
1586 for (Instruction *
I : ConditionalTemps)
1587 I->eraseFromParent();
1589 for (Instruction *
I : Origs) {
1595 for (DbgVariableRecord *Dbg : Dbgs) {
1596 auto &
DL =
I->getDataLayout();
1598 "We should've RAUW'd away loads, stores, etc. at this point");
1599 DbgVariableRecord *OffDbg =
Dbg->clone();
1600 auto [Rsrc,
Off] = getPtrParts(
I);
1602 int64_t RsrcSz =
DL.getTypeSizeInBits(Rsrc->
getType());
1603 int64_t OffSz =
DL.getTypeSizeInBits(
Off->getType());
1605 std::optional<DIExpression *> RsrcExpr =
1608 std::optional<DIExpression *> OffExpr =
1619 Dbg->setExpression(*RsrcExpr);
1620 Dbg->replaceVariableLocationOp(
I, Rsrc);
1627 I->replaceUsesWithIf(
Poison, [&](
const Use &U) ->
bool {
1633 if (
I->use_empty()) {
1634 I->eraseFromParent();
1637 IRB.SetInsertPoint(*
I->getInsertionPointAfterDef());
1638 IRB.SetCurrentDebugLocation(
I->getDebugLoc());
1639 auto [Rsrc,
Off] = getPtrParts(
I);
1641 Struct = IRB.CreateInsertValue(Struct, Rsrc, 0);
1642 Struct = IRB.CreateInsertValue(Struct, Off, 1);
1643 copyMetadata(Struct,
I);
1645 I->replaceAllUsesWith(Struct);
1646 I->eraseFromParent();
1650void SplitPtrStructs::setAlign(CallInst *Intr, Align
A,
unsigned RsrcArgIdx) {
1652 Intr->
addParamAttr(RsrcArgIdx, Attribute::getWithAlignment(Ctx,
A));
1658 case AtomicOrdering::Release:
1659 case AtomicOrdering::AcquireRelease:
1660 case AtomicOrdering::SequentiallyConsistent:
1661 IRB.CreateFence(AtomicOrdering::Release, SSID);
1671 case AtomicOrdering::Acquire:
1672 case AtomicOrdering::AcquireRelease:
1673 case AtomicOrdering::SequentiallyConsistent:
1674 IRB.CreateFence(AtomicOrdering::Acquire, SSID);
1681Value *SplitPtrStructs::handleMemoryInst(Instruction *
I,
Value *Arg,
Value *Ptr,
1682 Type *Ty, Align Alignment,
1685 IRB.SetInsertPoint(
I);
1687 auto [Rsrc,
Off] = getPtrParts(Ptr);
1690 Args.push_back(Arg);
1691 Args.push_back(Rsrc);
1692 Args.push_back(Off);
1693 insertPreMemOpFence(Order, SSID);
1697 Args.push_back(IRB.getInt32(0));
1702 Args.push_back(IRB.getInt32(Aux));
1706 IID = Order == AtomicOrdering::NotAtomic
1707 ? Intrinsic::amdgcn_raw_ptr_buffer_load
1708 : Intrinsic::amdgcn_raw_ptr_atomic_buffer_load;
1710 IID = Intrinsic::amdgcn_raw_ptr_buffer_store;
1712 switch (RMW->getOperation()) {
1714 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_swap;
1717 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_add;
1720 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_sub;
1723 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_and;
1726 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_or;
1729 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_xor;
1732 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_smax;
1735 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_smin;
1738 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_umax;
1741 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_umin;
1744 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_fadd;
1747 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_fmax;
1750 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_fmin;
1753 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_cond_sub_u32;
1756 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_sub_clamp_u32;
1760 "atomic floating point subtraction not supported for "
1761 "buffer resources and should've been expanded away");
1766 "atomic floating point fmaximum not supported for "
1767 "buffer resources and should've been expanded away");
1772 "atomic floating point fminimum not supported for "
1773 "buffer resources and should've been expanded away");
1778 "atomic nand not supported for buffer resources and "
1779 "should've been expanded away");
1784 "wrapping increment/decrement not supported for "
1785 "buffer resources and should've been expanded away");
1792 auto *
Call = IRB.CreateIntrinsic(IID, Ty, Args);
1793 copyMetadata(
Call,
I);
1794 setAlign(
Call, Alignment, Arg ? 1 : 0);
1797 insertPostMemOpFence(Order, SSID);
1801 I->replaceAllUsesWith(
Call);
1805PtrParts SplitPtrStructs::visitInstruction(Instruction &
I) {
1806 return {
nullptr,
nullptr};
1809PtrParts SplitPtrStructs::visitLoadInst(LoadInst &LI) {
1811 return {
nullptr,
nullptr};
1815 return {
nullptr,
nullptr};
1818PtrParts SplitPtrStructs::visitStoreInst(StoreInst &SI) {
1820 return {
nullptr,
nullptr};
1821 Value *Arg =
SI.getValueOperand();
1822 handleMemoryInst(&SI, Arg,
SI.getPointerOperand(), Arg->
getType(),
1823 SI.getAlign(),
SI.getOrdering(),
SI.isVolatile(),
1824 SI.getSyncScopeID());
1825 return {
nullptr,
nullptr};
1828PtrParts SplitPtrStructs::visitAtomicRMWInst(AtomicRMWInst &AI) {
1830 return {
nullptr,
nullptr};
1835 return {
nullptr,
nullptr};
1840PtrParts SplitPtrStructs::visitAtomicCmpXchgInst(AtomicCmpXchgInst &AI) {
1843 return {
nullptr,
nullptr};
1844 IRB.SetInsertPoint(&AI);
1849 bool IsNonTemporal = AI.
getMetadata(LLVMContext::MD_nontemporal);
1851 auto [Rsrc,
Off] = getPtrParts(Ptr);
1852 insertPreMemOpFence(Order, SSID);
1860 IRB.CreateIntrinsic(Intrinsic::amdgcn_raw_ptr_buffer_atomic_cmpswap, Ty,
1862 Off, IRB.getInt32(0), IRB.getInt32(Aux)});
1863 copyMetadata(
Call, &AI);
1866 insertPostMemOpFence(Order, SSID);
1869 Res = IRB.CreateInsertValue(Res,
Call, 0);
1872 Res = IRB.CreateInsertValue(Res, Succeeded, 1);
1876 return {
nullptr,
nullptr};
1879PtrParts SplitPtrStructs::visitGetElementPtrInst(GetElementPtrInst &
GEP) {
1880 using namespace llvm::PatternMatch;
1881 Value *Ptr =
GEP.getPointerOperand();
1883 return {
nullptr,
nullptr};
1884 IRB.SetInsertPoint(&
GEP);
1886 auto [Rsrc,
Off] = getPtrParts(Ptr);
1887 const DataLayout &
DL =
GEP.getDataLayout();
1888 bool IsNUW =
GEP.hasNoUnsignedWrap();
1889 bool IsNUSW =
GEP.hasNoUnsignedSignedWrap();
1900 GEP.mutateType(FatPtrTy);
1902 GEP.mutateType(ResTy);
1904 if (BroadcastsPtr) {
1905 Rsrc = IRB.CreateVectorSplat(ResRsrcVecTy->getElementCount(), Rsrc,
1907 Off = IRB.CreateVectorSplat(ResRsrcVecTy->getElementCount(), Off,
1915 bool HasNonNegativeOff =
false;
1917 HasNonNegativeOff = !CI->isNegative();
1923 NewOff = IRB.CreateAdd(Off, OffAccum,
"",
1924 IsNUW || (IsNUSW && HasNonNegativeOff),
1927 copyMetadata(NewOff, &
GEP);
1930 return {Rsrc, NewOff};
1933PtrParts SplitPtrStructs::visitPtrToIntInst(PtrToIntInst &PI) {
1936 return {
nullptr,
nullptr};
1937 IRB.SetInsertPoint(&PI);
1942 auto [Rsrc,
Off] = getPtrParts(Ptr);
1948 Res = IRB.CreateIntCast(Off, ResTy,
false,
1951 Value *RsrcInt = IRB.CreatePtrToInt(Rsrc, ResTy, PI.
getName() +
".rsrc");
1952 Value *Shl = IRB.CreateShl(
1955 "", Width >= FatPtrWidth, Width > FatPtrWidth);
1956 Value *OffCast = IRB.CreateIntCast(Off, ResTy,
false,
1958 Res = IRB.CreateOr(Shl, OffCast);
1961 copyMetadata(Res, &PI);
1965 return {
nullptr,
nullptr};
1968PtrParts SplitPtrStructs::visitPtrToAddrInst(PtrToAddrInst &PA) {
1971 return {
nullptr,
nullptr};
1972 IRB.SetInsertPoint(&PA);
1974 auto [Rsrc,
Off] = getPtrParts(Ptr);
1975 Value *Res = IRB.CreateIntCast(Off, PA.
getType(),
false);
1976 copyMetadata(Res, &PA);
1980 return {
nullptr,
nullptr};
1983PtrParts SplitPtrStructs::visitIntToPtrInst(IntToPtrInst &IP) {
1985 return {
nullptr,
nullptr};
1986 IRB.SetInsertPoint(&IP);
1995 Type *RsrcTy = RetTy->getElementType(0);
1996 Type *OffTy = RetTy->getElementType(1);
1997 Value *RsrcPart = IRB.CreateLShr(
2000 Value *RsrcInt = IRB.CreateIntCast(RsrcPart, RsrcIntTy,
false);
2001 Value *Rsrc = IRB.CreateIntToPtr(RsrcInt, RsrcTy, IP.
getName() +
".rsrc");
2003 IRB.CreateIntCast(
Int, OffTy,
false, IP.
getName() +
".off");
2005 copyMetadata(Rsrc, &IP);
2010PtrParts SplitPtrStructs::visitAddrSpaceCastInst(AddrSpaceCastInst &
I) {
2014 return {
nullptr,
nullptr};
2015 IRB.SetInsertPoint(&
I);
2018 if (
In->getType() ==
I.getType()) {
2019 auto [Rsrc,
Off] = getPtrParts(In);
2025 Type *RsrcTy = ResTy->getElementType(0);
2026 Type *OffTy = ResTy->getElementType(1);
2032 if (InConst && InConst->isNullValue()) {
2035 return {NullRsrc, ZeroOff};
2041 return {PoisonRsrc, PoisonOff};
2047 return {UndefRsrc, UndefOff};
2052 "only buffer resources (addrspace 8) and null/poison pointers can be "
2053 "cast to buffer fat pointers (addrspace 7)");
2055 return {
In, ZeroOff};
2058PtrParts SplitPtrStructs::visitICmpInst(ICmpInst &Cmp) {
2061 return {
nullptr,
nullptr};
2063 IRB.SetInsertPoint(&Cmp);
2064 ICmpInst::Predicate Pred =
Cmp.getPredicate();
2066 assert((Pred == ICmpInst::ICMP_EQ || Pred == ICmpInst::ICMP_NE) &&
2067 "Pointer comparison is only equal or unequal");
2068 auto [LhsRsrc, LhsOff] = getPtrParts(Lhs);
2069 auto [RhsRsrc, RhsOff] = getPtrParts(Rhs);
2070 Value *Res = IRB.CreateICmp(Pred, LhsOff, RhsOff);
2071 copyMetadata(Res, &Cmp);
2074 Cmp.replaceAllUsesWith(Res);
2075 return {
nullptr,
nullptr};
2078PtrParts SplitPtrStructs::visitFreezeInst(FreezeInst &
I) {
2080 return {
nullptr,
nullptr};
2081 IRB.SetInsertPoint(&
I);
2082 auto [Rsrc,
Off] = getPtrParts(
I.getOperand(0));
2084 Value *RsrcRes = IRB.CreateFreeze(Rsrc,
I.getName() +
".rsrc");
2085 copyMetadata(RsrcRes, &
I);
2086 Value *OffRes = IRB.CreateFreeze(Off,
I.getName() +
".off");
2087 copyMetadata(OffRes, &
I);
2089 return {RsrcRes, OffRes};
2092PtrParts SplitPtrStructs::visitExtractElementInst(ExtractElementInst &
I) {
2094 return {
nullptr,
nullptr};
2095 IRB.SetInsertPoint(&
I);
2096 Value *Vec =
I.getVectorOperand();
2097 Value *Idx =
I.getIndexOperand();
2098 auto [Rsrc,
Off] = getPtrParts(Vec);
2100 Value *RsrcRes = IRB.CreateExtractElement(Rsrc, Idx,
I.getName() +
".rsrc");
2101 copyMetadata(RsrcRes, &
I);
2102 Value *OffRes = IRB.CreateExtractElement(Off, Idx,
I.getName() +
".off");
2103 copyMetadata(OffRes, &
I);
2105 return {RsrcRes, OffRes};
2108PtrParts SplitPtrStructs::visitInsertElementInst(InsertElementInst &
I) {
2112 return {
nullptr,
nullptr};
2113 IRB.SetInsertPoint(&
I);
2114 Value *Vec =
I.getOperand(0);
2115 Value *Elem =
I.getOperand(1);
2116 Value *Idx =
I.getOperand(2);
2117 auto [VecRsrc, VecOff] = getPtrParts(Vec);
2118 auto [ElemRsrc, ElemOff] = getPtrParts(Elem);
2121 IRB.CreateInsertElement(VecRsrc, ElemRsrc, Idx,
I.getName() +
".rsrc");
2122 copyMetadata(RsrcRes, &
I);
2124 IRB.CreateInsertElement(VecOff, ElemOff, Idx,
I.getName() +
".off");
2125 copyMetadata(OffRes, &
I);
2127 return {RsrcRes, OffRes};
2130PtrParts SplitPtrStructs::visitShuffleVectorInst(ShuffleVectorInst &
I) {
2133 return {
nullptr,
nullptr};
2134 IRB.SetInsertPoint(&
I);
2136 Value *V1 =
I.getOperand(0);
2137 Value *V2 =
I.getOperand(1);
2138 ArrayRef<int>
Mask =
I.getShuffleMask();
2139 auto [V1Rsrc, V1Off] = getPtrParts(V1);
2140 auto [V2Rsrc, V2Off] = getPtrParts(V2);
2143 IRB.CreateShuffleVector(V1Rsrc, V2Rsrc, Mask,
I.getName() +
".rsrc");
2144 copyMetadata(RsrcRes, &
I);
2146 IRB.CreateShuffleVector(V1Off, V2Off, Mask,
I.getName() +
".off");
2147 copyMetadata(OffRes, &
I);
2149 return {RsrcRes, OffRes};
2152PtrParts SplitPtrStructs::visitPHINode(PHINode &
PHI) {
2154 return {
nullptr,
nullptr};
2155 IRB.SetInsertPoint(*
PHI.getInsertionPointAfterDef());
2161 Value *TmpRsrc = IRB.CreateExtractValue(&
PHI, 0,
PHI.getName() +
".rsrc");
2162 Value *TmpOff = IRB.CreateExtractValue(&
PHI, 1,
PHI.getName() +
".off");
2163 Conditionals.push_back(&
PHI);
2165 return {TmpRsrc, TmpOff};
2168PtrParts SplitPtrStructs::visitSelectInst(SelectInst &SI) {
2170 return {
nullptr,
nullptr};
2171 IRB.SetInsertPoint(&SI);
2174 Value *True =
SI.getTrueValue();
2175 Value *False =
SI.getFalseValue();
2176 auto [TrueRsrc, TrueOff] = getPtrParts(True);
2177 auto [FalseRsrc, FalseOff] = getPtrParts(False);
2180 IRB.CreateSelect(
Cond, TrueRsrc, FalseRsrc,
SI.getName() +
".rsrc", &SI);
2181 copyMetadata(RsrcRes, &SI);
2182 Conditionals.push_back(&SI);
2184 IRB.CreateSelect(
Cond, TrueOff, FalseOff,
SI.getName() +
".off", &SI);
2185 copyMetadata(OffRes, &SI);
2187 return {RsrcRes, OffRes};
2198 case Intrinsic::amdgcn_make_buffer_rsrc:
2199 case Intrinsic::ptrmask:
2200 case Intrinsic::invariant_start:
2201 case Intrinsic::invariant_end:
2202 case Intrinsic::launder_invariant_group:
2203 case Intrinsic::strip_invariant_group:
2204 case Intrinsic::memcpy:
2205 case Intrinsic::memcpy_inline:
2206 case Intrinsic::memmove:
2207 case Intrinsic::memset:
2208 case Intrinsic::memset_inline:
2209 case Intrinsic::experimental_memset_pattern:
2210 case Intrinsic::amdgcn_load_to_lds:
2211 case Intrinsic::amdgcn_load_async_to_lds:
2216PtrParts SplitPtrStructs::visitIntrinsicInst(IntrinsicInst &
I) {
2221 case Intrinsic::amdgcn_make_buffer_rsrc: {
2223 return {
nullptr,
nullptr};
2225 Value *Stride =
I.getArgOperand(1);
2226 Value *NumRecords =
I.getArgOperand(2);
2229 Type *RsrcType = SplitType->getElementType(0);
2230 Type *OffType = SplitType->getElementType(1);
2231 IRB.SetInsertPoint(&
I);
2232 Value *Rsrc = IRB.CreateIntrinsic(IID, {RsrcType,
Base->getType()},
2234 copyMetadata(Rsrc, &
I);
2238 return {Rsrc,
Zero};
2240 case Intrinsic::ptrmask: {
2241 Value *Ptr =
I.getArgOperand(0);
2243 return {
nullptr,
nullptr};
2245 IRB.SetInsertPoint(&
I);
2246 auto [Rsrc,
Off] = getPtrParts(Ptr);
2247 if (
Mask->getType() !=
Off->getType())
2249 "pointer (data layout not set up correctly?)");
2250 Value *OffRes = IRB.CreateAnd(Off, Mask,
I.getName() +
".off");
2251 copyMetadata(OffRes, &
I);
2253 return {Rsrc, OffRes};
2257 case Intrinsic::invariant_start: {
2258 Value *Ptr =
I.getArgOperand(1);
2260 return {
nullptr,
nullptr};
2261 IRB.SetInsertPoint(&
I);
2262 auto [Rsrc,
Off] = getPtrParts(Ptr);
2264 auto *NewRsrc = IRB.CreateIntrinsic(IID, {NewTy}, {
I.getOperand(0), Rsrc});
2265 copyMetadata(NewRsrc, &
I);
2268 I.replaceAllUsesWith(NewRsrc);
2269 return {
nullptr,
nullptr};
2271 case Intrinsic::invariant_end: {
2272 Value *RealPtr =
I.getArgOperand(2);
2274 return {
nullptr,
nullptr};
2275 IRB.SetInsertPoint(&
I);
2276 Value *RealRsrc = getPtrParts(RealPtr).first;
2277 Value *InvPtr =
I.getArgOperand(0);
2279 Value *NewRsrc = IRB.CreateIntrinsic(IID, {RealRsrc->
getType()},
2280 {InvPtr,
Size, RealRsrc});
2281 copyMetadata(NewRsrc, &
I);
2284 I.replaceAllUsesWith(NewRsrc);
2285 return {
nullptr,
nullptr};
2287 case Intrinsic::launder_invariant_group:
2288 case Intrinsic::strip_invariant_group: {
2289 Value *Ptr =
I.getArgOperand(0);
2291 return {
nullptr,
nullptr};
2292 IRB.SetInsertPoint(&
I);
2293 auto [Rsrc,
Off] = getPtrParts(Ptr);
2294 Value *NewRsrc = IRB.CreateIntrinsic(IID, {Rsrc->
getType()}, {Rsrc});
2295 copyMetadata(NewRsrc, &
I);
2298 return {NewRsrc,
Off};
2300 case Intrinsic::amdgcn_load_to_lds:
2301 case Intrinsic::amdgcn_load_async_to_lds: {
2302 Value *Ptr =
I.getArgOperand(0);
2304 return {
nullptr,
nullptr};
2305 IRB.SetInsertPoint(&
I);
2306 auto [Rsrc,
Off] = getPtrParts(Ptr);
2307 Value *LDSPtr =
I.getArgOperand(1);
2308 Value *LoadSize =
I.getArgOperand(2);
2309 Value *ImmOff =
I.getArgOperand(3);
2310 Value *Aux =
I.getArgOperand(4);
2311 Value *SOffset = IRB.getInt32(0);
2313 IID == Intrinsic::amdgcn_load_to_lds
2314 ? Intrinsic::amdgcn_raw_ptr_buffer_load_lds
2315 : Intrinsic::amdgcn_raw_ptr_buffer_load_async_lds;
2317 NewIntr, {}, {Rsrc, LDSPtr, LoadSize,
Off, SOffset, ImmOff, Aux});
2318 copyMetadata(NewLoad, &
I);
2320 I.replaceAllUsesWith(NewLoad);
2321 return {
nullptr,
nullptr};
2324 return {
nullptr,
nullptr};
2327void SplitPtrStructs::processFunction(Function &
F) {
2329 SmallVector<Instruction *, 0> Originals(
2331 LLVM_DEBUG(
dbgs() <<
"Splitting pointer structs in function: " <<
F.getName()
2333 for (Instruction *
I : Originals) {
2341 assert(((Rsrc && Off) || (!Rsrc && !Off)) &&
2342 "Can't have a resource but no offset");
2344 RsrcParts[
I] = Rsrc;
2348 processConditionals();
2349 killAndReplaceSplitInstructions(Originals);
2355 Conditionals.clear();
2356 ConditionalTemps.clear();
2360class AMDGPULowerBufferFatPointers :
public ModulePass {
2364 AMDGPULowerBufferFatPointers() : ModulePass(
ID) {}
2366 bool run(
Module &M,
const TargetMachine &TM);
2367 bool runOnModule(
Module &M)
override;
2369 void getAnalysisUsage(AnalysisUsage &AU)
const override;
2377 BufferFatPtrToStructTypeMap *TypeMap) {
2378 bool HasFatPointers =
false;
2381 HasFatPointers |= (
I.getType() != TypeMap->remapType(
I.getType()));
2383 for (
const Value *V :
I.operand_values())
2384 HasFatPointers |= (V->getType() != TypeMap->remapType(V->getType()));
2386 return HasFatPointers;
2390 BufferFatPtrToStructTypeMap *TypeMap) {
2391 Type *Ty =
F.getFunctionType();
2392 return Ty != TypeMap->remapType(Ty);
2408 while (!OldF->
empty()) {
2422 CloneMap[&NewArg] = &OldArg;
2423 NewArg.takeName(&OldArg);
2424 Type *OldArgTy = OldArg.getType(), *NewArgTy = NewArg.getType();
2426 NewArg.mutateType(OldArgTy);
2427 OldArg.replaceAllUsesWith(&NewArg);
2428 NewArg.mutateType(NewArgTy);
2432 if (OldArgTy != NewArgTy && !IsIntrinsic)
2435 AttributeFuncs::typeIncompatible(NewArgTy, ArgAttr));
2442 AttributeFuncs::typeIncompatible(NewF->
getReturnType(), RetAttrs));
2444 NewF->
getContext(), OldAttrs.getFnAttrs(), RetAttrs, ArgAttrs));
2452 CloneMap[&BB] = &BB;
2458bool AMDGPULowerBufferFatPointers::run(
Module &M,
const TargetMachine &TM) {
2460 const DataLayout &
DL =
M.getDataLayout();
2466 LLVMContext &Ctx =
M.getContext();
2468 BufferFatPtrToStructTypeMap StructTM(
DL);
2469 BufferFatPtrToIntTypeMap IntTM(
DL);
2470 for (
const GlobalVariable &GV :
M.globals()) {
2473 Ctx.
emitError(
"global variables with a buffer fat pointer address "
2474 "space (7) are not supported");
2478 Type *VT = GV.getValueType();
2479 if (VT != StructTM.remapType(VT)) {
2481 Ctx.
emitError(
"global variables that contain buffer fat pointers "
2482 "(address space 7 pointers) are unsupported. Use "
2483 "buffer resource pointers (address space 8) instead");
2491 for (Function &
F :
M.functions())
2498 SmallPtrSet<Constant *, 8> Visited;
2499 SetVector<Constant *> BufferFatPtrConsts;
2500 while (!Worklist.
empty()) {
2502 if (!Visited.
insert(
C).second)
2518 StoreFatPtrsAsIntsAndExpandMemcpyVisitor MemOpsRewrite(&IntTM,
DL,
2519 M.getContext(), &TM);
2520 LegalizeBufferContentTypesVisitor BufferContentsTypeRewrite(
DL,
2522 for (Function &
F :
M.functions()) {
2525 Changed |= MemOpsRewrite.processFunction(
F);
2526 if (InterfaceChange || BodyChanges) {
2527 NeedsRemap.
push_back(std::make_pair(&
F, InterfaceChange));
2528 Changed |= BufferContentsTypeRewrite.processFunction(
F);
2531 if (NeedsRemap.
empty())
2538 FatPtrConstMaterializer Materializer(&StructTM, CloneMap);
2540 ValueMapper LowerInFuncs(CloneMap,
RF_None, &StructTM, &Materializer);
2541 for (
auto [
F, InterfaceChange] : NeedsRemap) {
2543 if (InterfaceChange)
2549 LowerInFuncs.remapFunction(*NewF);
2554 if (InterfaceChange) {
2555 F->replaceAllUsesWith(NewF);
2556 F->eraseFromParent();
2564 SplitPtrStructs Splitter(
DL,
M.getContext(), &TM);
2565 for (Function *
F : NeedsPostProcess)
2566 Splitter.processFunction(*
F);
2567 for (Function *
F : Intrinsics) {
2571 F->eraseFromParent();
2575 F->replaceAllUsesWith(*NewF);
2581bool AMDGPULowerBufferFatPointers::runOnModule(
Module &M) {
2582 TargetPassConfig &TPC = getAnalysis<TargetPassConfig>();
2583 const TargetMachine &TM = TPC.
getTM<TargetMachine>();
2587char AMDGPULowerBufferFatPointers::ID = 0;
2591void AMDGPULowerBufferFatPointers::getAnalysisUsage(
AnalysisUsage &AU)
const {
2595#define PASS_DESC "Lower buffer fat pointer operations to buffer resources"
2604 return new AMDGPULowerBufferFatPointers();
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
AMDGPU address space definition.
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
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.
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
void visit(MachineFunction &MF, MachineBasicBlock &Start, std::function< void(MachineBasicBlock *)> 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.
This class represents a conversion between pointers from one address space to another.
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.
bool isWeak() const
Return true if this cmpxchg may spuriously fail.
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
@ FMax
*p = maxnum(old, v) maxnum matches the behavior of llvm.maxnum.
@ UDecWrap
Decrement one until a minimum value or zero.
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 ...
static GEPNoWrapFlags noUnsignedWrap()
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.
LLVM_ABI const Function * getFunction() const
Return the function this instruction belongs to.
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.
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
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.
virtual TargetTransformInfo getTargetTransformInfo(const Function &F) const
Return a TargetTransformInfo for a given function.
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)
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 ScalarTy getFixedValue() const
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 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.
PointerTypeMap run(const Module &M)
Compute the PointerTypeMap for the module M.
friend class Instruction
Iterator for Instructions in a `BasicBlock.
This is an optimization pass for GlobalISel generic memory operations.
detail::zippy< detail::zip_shortest, T, U, Args... > zip(T &&t, U &&u, Args &&...args)
zip iterator for two or more iteratable types.
FunctionAddr VTableAddr Value
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 expandMemSetPatternAsLoop(MemSetPatternInst *MemSet)
Expand MemSetPattern as a loop. MemSet is not deleted.
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...
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.
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.
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.