Commit 9d878480 authored by jsantill's avatar jsantill Committed by gbsbuild

Promote accesses to array of bindless textures to indirect binding table. If...

Promote accesses to array of bindless textures to indirect binding table. If all accesses are promoted, an array may be removed, which saves private memory usage.

Change-Id: I7720b0c14f1f84d69c741efe8f11b46f70097afc
parent cfafdf9f
......@@ -73,6 +73,7 @@ CheckInstrTypes::CheckInstrTypes(IGC::SInstrTypes* instrList) : FunctionPass(ID)
instrList->hasSubroutines = false;
instrList->hasPrimitiveAlloca = false;
instrList->hasNonPrimitiveAlloca = false;
instrList->hasReadOnlyArray = false;
instrList->hasBuiltin = false;
instrList->psHasSideEffect = false;
instrList->hasDebugInfo = false;
......@@ -254,6 +255,11 @@ void CheckInstrTypes::visitAllocaInst(AllocaInst &I)
g_InstrTypes->hasPrimitiveAlloca = true;
}
if (auto md = I.getMetadata("igc.read_only_array"))
{
g_InstrTypes->hasReadOnlyArray = true;
}
auto PT = dyn_cast<PointerType>(I.getAllocatedType());
if (PT && PT->getPointerAddressSpace() == ADDRESS_SPACE_GENERIC)
{
......
......@@ -13882,6 +13882,18 @@ ResourceDescriptor EmitPass::GetResourceVariable(Value* resourcePtr)
resource.m_resource = GetSymbol(resourcePtr);
}
if (resource.m_resource->GetElemSize() < 4)
{
// vISA assumes all BTIs to be 32 bit. Need to cast, otherwise higher bits would be uninitialized.
CVariable* newResource = m_currShader->GetNewVariable(
resource.m_resource->GetNumberElement(),
ISA_TYPE_UD,
resource.m_resource->GetAlign(),
resource.m_resource->IsUniform());
m_encoder->Cast(newResource, resource.m_resource);
resource.m_resource = newResource;
}
if (!directIndexing)
{
m_currShader->SetBindingTableEntryCountAndBitmap(false);
......
......@@ -411,6 +411,11 @@ inline void AddLegalizationPasses(CodeGenContext &ctx, IGCPassManager& mpm)
// Promotes indirect resource access to direct
mpm.add(new PromoteResourceToDirectAS());
if (ctx.m_instrTypes.hasReadOnlyArray)
{
mpm.add(createDeadCodeEliminationPass());
mpm.add(createSROAPass());
}
if (ctx.m_instrTypes.hasGenericAddressSpacePointers)
{
......
......@@ -341,6 +341,15 @@ Value* TracePointerSource(Value* resourcePtr, bool hasBranching, bool fillList,
srcPtr = baseValue;
break;
}
else if (auto allocaInst = dyn_cast<AllocaInst>(baseValue))
{
if (auto md = allocaInst->getMetadata("igc.read_only_array"))
{
// Found alloca marked as read_only array.
srcPtr = baseValue;
}
break;
}
else if (CastInst* inst = dyn_cast<CastInst>(baseValue))
{
baseValue = inst->getOperand(0);
......@@ -406,6 +415,18 @@ Value* TracePointerSource(Value* resourcePtr, bool hasBranching, bool fillList,
}
return nullptr;
}
else if(LoadInst *inst = dyn_cast<LoadInst>(baseValue))
{
if (inst->getPointerAddressSpace() == 0)
{
// May be local array of resources:
baseValue = inst->getPointerOperand();
}
else
{
break;
}
}
else
{
// Unsupported instruction in search chain. Don't continue.
......
......@@ -142,6 +142,7 @@ namespace IGC
bool hasSubroutines;
bool hasPrimitiveAlloca;
bool hasNonPrimitiveAlloca;
bool hasReadOnlyArray;
bool hasBuiltin;
bool psHasSideEffect; //<! only relevant to pixel shader, has other memory writes besides RTWrite
bool hasGenericAddressSpacePointers;
......
......@@ -172,6 +172,83 @@ Type* GetBufferAccessType(Instruction *inst)
return inst->getType();
}
Argument* FindArrayBaseArg(AllocaInst* alloca)
{
// Search for argument that is first element of this local array, starting from alloca.
// This is pattern match and is relying on a way array is lowered.
// First, find GEP taking first element of an array. It is assumed to be immediate user of alloca.
Argument* arg = nullptr;
GetElementPtrInst* baseGep = nullptr;
for(Value::user_iterator use_it = alloca->user_begin(), use_e = alloca->user_end(); use_it != use_e; ++use_it)
{
if(auto gep = dyn_cast<GetElementPtrInst>(*use_it))
{
if (gep->getNumIndices() == 2)
{
if (auto gepIndexValue = dyn_cast<llvm::ConstantInt>(gep->getOperand(2)))
{
if (gepIndexValue->getZExtValue() == 0)
{
// Pointer to first element found.
baseGep = gep;
}
}
}
}
}
// The only user for this GEP should be a store, which is storing function argument to an array.
// Note that this is assuming OCL approach, which is using KernelArgs.
if (baseGep && baseGep->hasOneUse())
{
if (auto store = dyn_cast<StoreInst>(*baseGep->user_begin()))
{
if (auto elem = dyn_cast<Argument>(store->getValueOperand()))
{
arg = elem;
}
}
}
return arg;
}
Value* FindArrayIndex(const std::vector<Value*>& instList, IGCIRBuilder<>& builder)
{
// Find GEP instruction in the list and get arrayIndex from it, depending on GEP type.
Value* arrayIndex = nullptr;
for (Value* V : instList)
{
if (auto gep = dyn_cast<GetElementPtrInst>(V))
{
if (arrayIndex != nullptr || gep->getPointerAddressSpace() != 0)
{
// It's not expected to see multiple GEPs on this path or GEPs to addrspace other than 0.
arrayIndex = nullptr;
break;
}
auto pointerElementTy = gep->getPointerOperandType()->getPointerElementType();
if (pointerElementTy->isStructTy())
{
// Example: %1 = getelementptr inbounds %"struct.texture", %"struct.texture"* %aot, i64 %arrayIndex, i32 0
arrayIndex = gep->getOperand(1);
}
else if(pointerElementTy->isArrayTy() && gep->getOperand(1) == builder.getInt64(0))
{
// Example: %2 = getelementptr inbounds [8 x %"struct.texture"], [8 x %"struct.texture"]* %aot, i64 0, i64 %arrayIndex, i32 0
arrayIndex = gep->getOperand(2);
}
else if(pointerElementTy->isPointerTy() && pointerElementTy->getPointerElementType()->isStructTy() && gep->getOperand(1) == builder.getInt64(0))
{
// Example: %3 = getelementptr inbounds %"struct.texture", %"struct.texture"** %aot, i64 0, i64 %arrayIndex, i32 0
arrayIndex = gep->getOperand(2);
}
}
}
return arrayIndex;
}
void PromoteResourceToDirectAS::PromoteSamplerTextureToDirectAS(GenIntrinsicInst *&pIntr, Value* resourcePtr)
{
IGCIRBuilder<> builder(pIntr);
......@@ -188,10 +265,30 @@ void PromoteResourceToDirectAS::PromoteSamplerTextureToDirectAS(GenIntrinsicInst
BufferType bufTy;
BufferAccessType accTy;
bool canPromote = false;
Value* srcPtr = IGC::TracePointerSource(resourcePtr);
Value* arrayIndex = nullptr;
std::vector<Value*> instList;
Value* srcPtr = IGC::TracePointerSource(resourcePtr, false, true, instList);
if (srcPtr)
{
if (auto alloca = llvm::dyn_cast<AllocaInst>(srcPtr))
{
arrayIndex = FindArrayIndex(instList, builder);
if (arrayIndex != nullptr)
{
// TODO: We could read igc.read_only_array metadata attached to alloca.
// If not -1, it should contain base index of this array. In this case,
// FindArrayBaseArg would not be needed.
// Find input argument for the first element in this array.
srcPtr = FindArrayBaseArg(alloca);
}
}
}
if (srcPtr)
{
// Trace the resource pointer.
// If we can find it, we can promote the indirect access to direct access
// by encoding the BTI as a direct addrspace
......@@ -236,9 +333,30 @@ void PromoteResourceToDirectAS::PromoteSamplerTextureToDirectAS(GenIntrinsicInst
if (canPromote)
{
addrSpace = IGC::EncodeAS4GFXResource(*builder.getInt32(bufID), bufTy, 0);
Value* bufferId = builder.getInt32(bufID);
if (arrayIndex != nullptr)
{
// Add base array index:
if (arrayIndex->getType() != bufferId->getType())
{
arrayIndex = builder.CreateZExtOrTrunc(arrayIndex, bufferId->getType());
}
bufferId = builder.CreateAdd(bufferId, arrayIndex);
}
addrSpace = IGC::EncodeAS4GFXResource(*bufferId, bufTy, 0);
PointerType* newptrType = PointerType::get(resourcePtr->getType()->getPointerElementType(), addrSpace);
Constant* mutePtr = ConstantPointerNull::get(newptrType);
Value* mutePtr = nullptr;
if (llvm::isa<llvm::ConstantInt>(bufferId))
{
mutePtr = ConstantPointerNull::get(newptrType);
}
else
{
// Index is not a constant:
mutePtr = builder.CreateIntToPtr(builder.CreateZExt(bufferId, builder.getInt64Ty()), newptrType);
}
IGC::ChangePtrTypeInIntrinsic(pIntr, resourcePtr, mutePtr);
}
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment