[llvm] [DirectX] Handle dx.RawBuffer in DXILResourceAccess (PR #121725)
Justin Bogner via llvm-commits
llvm-commits at lists.llvm.org
Thu Jan 23 21:35:32 PST 2025
================
@@ -21,99 +21,206 @@
using namespace llvm;
-static void replaceTypedBufferAccess(IntrinsicInst *II,
- dxil::ResourceTypeInfo &RTI) {
- const DataLayout &DL = II->getDataLayout();
+static Value *calculateGEPOffset(GetElementPtrInst *GEP, Value *PrevOffset,
+ dxil::ResourceTypeInfo &RTI) {
+ assert(!PrevOffset && "Non-constant GEP chains not handled yet");
+
+ const DataLayout &DL = GEP->getDataLayout();
+
+ uint64_t ScalarSize = 1;
+ if (RTI.isTyped()) {
+ Type *ContainedType = RTI.getHandleTy()->getTypeParameter(0);
+ // We need the size of an element in bytes so that we can calculate the
+ // offset in elements given a total offset in bytes.
+ Type *ScalarType = ContainedType->getScalarType();
+ ScalarSize = DL.getTypeSizeInBits(ScalarType) / 8;
+ }
+
+ APInt ConstantOffset(DL.getIndexTypeSizeInBits(GEP->getType()), 0);
+ if (GEP->accumulateConstantOffset(DL, ConstantOffset)) {
+ APInt Scaled = ConstantOffset.udiv(ScalarSize);
+ return ConstantInt::get(Type::getInt32Ty(GEP->getContext()), Scaled);
+ }
+
+ auto IndexIt = GEP->idx_begin();
+ assert(cast<ConstantInt>(IndexIt)->getZExtValue() == 0 &&
+ "GEP is not indexing through pointer");
+ ++IndexIt;
+ Value *Offset = *IndexIt;
+ assert(++IndexIt == GEP->idx_end() && "Too many indices in GEP");
+ return Offset;
+}
+
+static void createTypedBufferStore(IntrinsicInst *II, StoreInst *SI,
+ Value *Offset, dxil::ResourceTypeInfo &RTI) {
+ IRBuilder<> Builder(SI);
+ Type *ContainedType = RTI.getHandleTy()->getTypeParameter(0);
+ Type *LoadType = StructType::get(ContainedType, Builder.getInt1Ty());
+
+ Value *V = SI->getValueOperand();
+ if (V->getType() == ContainedType) {
+ // V is already the right type.
+ assert(!Offset && "store of whole element has offset?");
+ } else if (V->getType() == ContainedType->getScalarType()) {
+ // We're storing a scalar, so we need to load the current value and only
+ // replace the relevant part.
+ auto *Load = Builder.CreateIntrinsic(
+ LoadType, Intrinsic::dx_resource_load_typedbuffer,
+ {II->getOperand(0), II->getOperand(1)});
+ auto *Struct = Builder.CreateExtractValue(Load, {0});
+
+ // If we have an offset from seeing a GEP earlier, use that. Otherwise, 0.
+ if (!Offset)
+ Offset = ConstantInt::get(Builder.getInt32Ty(), 0);
+ V = Builder.CreateInsertElement(Struct, V, Offset);
+ } else {
+ llvm_unreachable("Store to typed resource has invalid type");
+ }
+
+ auto *Inst = Builder.CreateIntrinsic(
+ Builder.getVoidTy(), Intrinsic::dx_resource_store_typedbuffer,
+ {II->getOperand(0), II->getOperand(1), V});
+ SI->replaceAllUsesWith(Inst);
+}
+
+static void createRawStore(IntrinsicInst *II, StoreInst *SI, Value *Offset) {
+ IRBuilder<> Builder(SI);
+
+ if (!Offset)
+ Offset = ConstantInt::get(Builder.getInt32Ty(), 0);
+ Value *V = SI->getValueOperand();
+ // TODO: break up larger types
+ auto *Inst = Builder.CreateIntrinsic(
+ Builder.getVoidTy(), Intrinsic::dx_resource_store_rawbuffer,
+ {II->getOperand(0), II->getOperand(1), Offset, V});
+ SI->replaceAllUsesWith(Inst);
+}
+
+static void createStoreIntrinsic(IntrinsicInst *II, StoreInst *SI,
+ Value *Offset, dxil::ResourceTypeInfo &RTI) {
+ switch (RTI.getResourceKind()) {
+ case dxil::ResourceKind::TypedBuffer:
+ return createTypedBufferStore(II, SI, Offset, RTI);
+ case dxil::ResourceKind::RawBuffer:
+ case dxil::ResourceKind::StructuredBuffer:
+ return createRawStore(II, SI, Offset);
+ case dxil::ResourceKind::Texture1D:
+ case dxil::ResourceKind::Texture2D:
+ case dxil::ResourceKind::Texture2DMS:
+ case dxil::ResourceKind::Texture3D:
+ case dxil::ResourceKind::TextureCube:
+ case dxil::ResourceKind::Texture1DArray:
+ case dxil::ResourceKind::Texture2DArray:
+ case dxil::ResourceKind::Texture2DMSArray:
+ case dxil::ResourceKind::TextureCubeArray:
+ case dxil::ResourceKind::FeedbackTexture2D:
+ case dxil::ResourceKind::FeedbackTexture2DArray:
+ // TODO: handle these
+ return;
+ case dxil::ResourceKind::CBuffer:
+ case dxil::ResourceKind::Sampler:
+ case dxil::ResourceKind::TBuffer:
+ case dxil::ResourceKind::RTAccelerationStructure:
+ case dxil::ResourceKind::Invalid:
+ case dxil::ResourceKind::NumEntries:
+ llvm_unreachable("Invalid resource kind for store");
+ }
+ llvm_unreachable("Unhandled case in switch");
+}
+
+static void createTypedBufferLoad(IntrinsicInst *II, LoadInst *LI,
+ Value *Offset, dxil::ResourceTypeInfo &RTI) {
+ IRBuilder<> Builder(LI);
+ Type *ContainedType = RTI.getHandleTy()->getTypeParameter(0);
+ Type *LoadType = StructType::get(ContainedType, Builder.getInt1Ty());
- auto *HandleType = cast<TargetExtType>(II->getOperand(0)->getType());
- assert(HandleType->getName() == "dx.TypedBuffer" &&
- "Unexpected typed buffer type");
- Type *ContainedType = HandleType->getTypeParameter(0);
+ Value *V =
+ Builder.CreateIntrinsic(LoadType, Intrinsic::dx_resource_load_typedbuffer,
+ {II->getOperand(0), II->getOperand(1)});
+ V = Builder.CreateExtractValue(V, {0});
- Type *LoadType =
- StructType::get(ContainedType, Type::getInt1Ty(II->getContext()));
+ if (Offset)
+ V = Builder.CreateExtractElement(V, Offset);
- // We need the size of an element in bytes so that we can calculate the offset
- // in elements given a total offset in bytes later.
- Type *ScalarType = ContainedType->getScalarType();
- uint64_t ScalarSize = DL.getTypeSizeInBits(ScalarType) / 8;
+ LI->replaceAllUsesWith(V);
+}
+static void createRawLoad(IntrinsicInst *II, LoadInst *LI, Value *Offset) {
+ IRBuilder<> Builder(LI);
+ // TODO: break up larger types
----------------
bogner wrote:
I tried a few ways but the assert here is a little tricky to formulate, and we don't really end up with invalid DXIL anyway since the lowering of the load will fail if we get anything really silly here. I think I'll leave it as is for now.
https://github.com/llvm/llvm-project/pull/121725
More information about the llvm-commits
mailing list