[llvm] Lower llvm.dx.rawBufferLoad to dxil ops (PR #116845)

via llvm-commits llvm-commits at lists.llvm.org
Tue Nov 19 10:32:00 PST 2024


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-llvm-analysis

Author: Zhengxing li (lizhengxing)

<details>
<summary>Changes</summary>

It's the draft PR of llvm.dx.rawbufferload.

There are 3 commits. 
The DXILResourceMap change: [[[DirectX] Add Resource uses to Resource Handle map in DXILResourceMap · lizhengxing/llvm-project@<!-- -->392daa1](https://github.com/lizhengxing/llvm-project/commit/392daa10503f89a2f081ec2df2fea5ea5db980f6)](https://github.com/llvm/llvm-project/pull/116845/commits/8e1bca0aa7269bcb210d2e5e1a95e7d8375ba162)
The Raw Buffer Load  change: [[Lower llvm.dx.rawbufferload to dxil ops · lizhengxing/llvm-project@<!-- -->731703f](https://github.com/lizhengxing/llvm-project/commit/731703f8130d47d5d2e3b89ff413ef7d4d38523e)](https://github.com/llvm/llvm-project/pull/116845/commits/27c361bd7cf21506e46b074c59a57bbd6c60ceb1)
 
I separate the DXILResourceMap change in the Raw Buffer Load PR to the third commit. [[Changes in DXILResourceMap for lowering llvm.dx.rawbufferload to dxil… · lizhengxing/llvm-project@<!-- -->5abec9d](https://github.com/lizhengxing/llvm-project/commit/5abec9db0adc2203355478e524dcc651336c3f40)](https://github.com/llvm/llvm-project/pull/116845/commits/3a8f3a1996ed2c87aae08632fcb4fc08893cfae1)

---

Patch is 30.48 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/116845.diff


8 Files Affected:

- (modified) llvm/include/llvm/Analysis/DXILResource.h (+32) 
- (modified) llvm/include/llvm/IR/IntrinsicsDirectX.td (+3) 
- (modified) llvm/lib/Analysis/DXILResource.cpp (+69) 
- (modified) llvm/lib/Target/DirectX/DXIL.td (+11) 
- (modified) llvm/lib/Target/DirectX/DXILOpLowering.cpp (+199) 
- (added) llvm/test/Analysis/DXILResource/resource-map.ll (+36) 
- (added) llvm/test/CodeGen/DirectX/DXILResource/dxil-resource-map.ll (+48) 
- (added) llvm/test/CodeGen/DirectX/RawBufferLoad.ll (+192) 


``````````diff
diff --git a/llvm/include/llvm/Analysis/DXILResource.h b/llvm/include/llvm/Analysis/DXILResource.h
index 6b577c02f05450..7f64688fba183a 100644
--- a/llvm/include/llvm/Analysis/DXILResource.h
+++ b/llvm/include/llvm/Analysis/DXILResource.h
@@ -264,6 +264,8 @@ class ResourceInfo {
 class DXILResourceMap {
   SmallVector<dxil::ResourceInfo> Resources;
   DenseMap<CallInst *, unsigned> CallMap;
+  // Mapping from Resource use to Resource Handle
+  DenseMap<CallInst *, CallInst *> ResUseToHandleMap;
   unsigned FirstUAV = 0;
   unsigned FirstCBuffer = 0;
   unsigned FirstSampler = 0;
@@ -335,6 +337,36 @@ class DXILResourceMap {
   }
 
   void print(raw_ostream &OS) const;
+
+  void updateResourceMap(CallInst *origCallInst, CallInst *newCallInst);
+
+  // Update ResUseMap with multiple new resource uses
+  void updateResUseMap(CallInst *origResUse,
+                       std::vector<Value *> &multiNewResUse);
+
+  // Update ResUseMap with single new resource use
+  void updateResUseMap(CallInst *origResUse, CallInst *newResUse) {
+    assert((origResUse != nullptr) && (newResUse != nullptr) &&
+           (origResUse != newResUse) && "Wrong Inputs");
+
+    updateResUseMapCommon(origResUse, newResUse, /*keepOrigResUseInMap=*/false);
+  }
+
+  CallInst *findResHandleByUse(CallInst *resUse) {
+    auto Pos = ResUseToHandleMap.find(resUse);
+    assert((Pos != ResUseToHandleMap.end()) &&
+           "Can't find the resource handle");
+
+    return Pos->second;
+  }
+
+private:
+  void updateResUseMapCommon(CallInst *origResUse, CallInst *newResUse,
+                             bool keepOrigResUseInMap) {
+    ResUseToHandleMap.try_emplace(newResUse, findResHandleByUse(origResUse));
+    if (!keepOrigResUseInMap)
+      ResUseToHandleMap.erase(origResUse);
+  }
 };
 
 class DXILResourceAnalysis : public AnalysisInfoMixin<DXILResourceAnalysis> {
diff --git a/llvm/include/llvm/IR/IntrinsicsDirectX.td b/llvm/include/llvm/IR/IntrinsicsDirectX.td
index 48a9595f844f05..d8be8d002a0917 100644
--- a/llvm/include/llvm/IR/IntrinsicsDirectX.td
+++ b/llvm/include/llvm/IR/IntrinsicsDirectX.td
@@ -27,6 +27,9 @@ def int_dx_handle_fromBinding
           [llvm_i32_ty, llvm_i32_ty, llvm_i32_ty, llvm_i32_ty, llvm_i1_ty],
           [IntrNoMem]>;
 
+def int_dx_rawBufferLoad
+    : DefaultAttrsIntrinsic<[llvm_any_ty], [llvm_any_ty, llvm_i32_ty, llvm_i32_ty]>;
+
 def int_dx_typedBufferLoad
     : DefaultAttrsIntrinsic<[llvm_any_ty], [llvm_any_ty, llvm_i32_ty],
                             [IntrReadMem]>;
diff --git a/llvm/lib/Analysis/DXILResource.cpp b/llvm/lib/Analysis/DXILResource.cpp
index 2802480481690d..be4fad8a84a171 100644
--- a/llvm/lib/Analysis/DXILResource.cpp
+++ b/llvm/lib/Analysis/DXILResource.cpp
@@ -719,6 +719,12 @@ DXILResourceMap::DXILResourceMap(
     if (Resources.empty() || RI != Resources.back())
       Resources.push_back(RI);
     CallMap[CI] = Resources.size() - 1;
+
+    // Build ResUseToHandleMap
+    for (auto it = CI->users().begin(); it != CI->users().end(); ++it) {
+      CallInst *CI_Use = dyn_cast<CallInst>(*it);
+      ResUseToHandleMap[CI_Use] = CI;
+    }
   }
 
   unsigned Size = Resources.size();
@@ -744,6 +750,61 @@ DXILResourceMap::DXILResourceMap(
   }
 }
 
+// Parameter origCallInst: original Resource Handle
+// Parameter newCallInst:  new Resource Handle
+//
+// This function is needed when origCallInst's lowered to newCallInst.
+//
+// Because origCallInst and its uses will be replaced by newCallInst and new def
+// instructions after lowering. The [origCallInst, resource info] entry in
+// CallMap and [origCallInst's use, origCallInst] entries in ResUseToHandleMap
+// have to be updated per the changes in lowering.
+//
+// What this function does are:
+//   1. Add [newCallInst, resource info] entry in CallMap
+//   2. Remove [origCallInst, resource info] entry in CallMap
+//   3. Remap [origCallInst's use, origCallInst] entries to
+//      [origCallInst's use, newCallInst] entries in ResUseToHandleMap
+//
+// Remove those entries related to origCallInst in maps is necessary since
+// origCallInst's no longer existing after lowering. Moreover, keeping those
+// entries in maps will crash DXILResourceMap::print function
+//
+// FYI:
+// Make sure to invoke this function before origCallInst->replaceAllUsesWith()
+// and origCallInst->eraseFromParent() since this function needs to visit
+// origCallInst and its uses.
+//
+void DXILResourceMap::updateResourceMap(CallInst *origCallInst,
+                                        CallInst *newCallInst) {
+  assert((origCallInst != nullptr) && (newCallInst != nullptr) &&
+         (origCallInst != newCallInst));
+
+  CallMap.try_emplace(newCallInst, CallMap[origCallInst]);
+  CallMap.erase(origCallInst);
+
+  // Update ResUseToHandleMap since Resource Handle changed
+  for (auto it = origCallInst->users().begin();
+       it != origCallInst->users().end(); ++it) {
+    CallInst *CI_Use = dyn_cast<CallInst>(*it);
+    ResUseToHandleMap[CI_Use] = newCallInst;
+  }
+}
+
+  void DXILResourceMap::updateResUseMap(CallInst *origResUse,
+                                      std::vector<Value *> &multiNewResUse) {
+    assert((origResUse != nullptr) && "Wrong Inputs");
+
+    for (int i = 0; i < multiNewResUse.size(); ++i) {
+      CallInst *newResUse = dyn_cast<CallInst>(multiNewResUse[i]);
+      assert(newResUse != nullptr);
+
+      bool keepOrigResUseInMap =
+          i == (multiNewResUse.size() - 1) ? false : true;
+      updateResUseMapCommon(origResUse, newResUse, keepOrigResUseInMap);
+    }
+  }
+
 void DXILResourceMap::print(raw_ostream &OS) const {
   for (unsigned I = 0, E = Resources.size(); I != E; ++I) {
     OS << "Binding " << I << ":\n";
@@ -756,6 +817,14 @@ void DXILResourceMap::print(raw_ostream &OS) const {
     CI->print(OS);
     OS << "\n";
   }
+
+  for (const auto &[ResUse, ResHandle] : ResUseToHandleMap) {
+    OS << "\n";
+    OS << "Resource " << CallMap.find(ResHandle)->second;
+    OS << " is used by ";
+    ResUse->print(OS);
+    OS << "\n";
+  }
 }
 
 //===----------------------------------------------------------------------===//
diff --git a/llvm/lib/Target/DirectX/DXIL.td b/llvm/lib/Target/DirectX/DXIL.td
index 1a8e110491cc87..a638371d6031ad 100644
--- a/llvm/lib/Target/DirectX/DXIL.td
+++ b/llvm/lib/Target/DirectX/DXIL.td
@@ -854,6 +854,17 @@ def AnnotateHandle : DXILOp<216, annotateHandle> {
   let stages = [Stages<DXIL1_6, [all_stages]>];
 }
 
+def RawBufferLoad : DXILOp<139, rawBufferLoad> {
+  let Doc = "reads from a ByteAddressBuffer or StructuredBuffer";
+  // Handle, Coord0, Coord1, mask, alignment
+  let arguments = [HandleTy, Int32Ty, Int32Ty, Int8Ty, Int32Ty];
+  let result = OverloadTy;
+  let overloads =
+      [Overloads<DXIL1_0,
+                 [ResRetHalfTy, ResRetFloatTy, ResRetInt16Ty, ResRetInt32Ty]>];
+  let stages = [Stages<DXIL1_0, [all_stages]>];
+}
+
 def CreateHandleFromBinding : DXILOp<217, createHandleFromBinding> {
   let Doc = "create resource handle from binding";
   let arguments = [ResBindTy, Int32Ty, Int1Ty];
diff --git a/llvm/lib/Target/DirectX/DXILOpLowering.cpp b/llvm/lib/Target/DirectX/DXILOpLowering.cpp
index 9f124394363a38..d2b6f05fc936bd 100644
--- a/llvm/lib/Target/DirectX/DXILOpLowering.cpp
+++ b/llvm/lib/Target/DirectX/DXILOpLowering.cpp
@@ -249,6 +249,8 @@ class OpLowerer {
 
       removeResourceGlobals(CI);
 
+      DRM.updateResourceMap(CI, *OpCall);
+
       CI->replaceAllUsesWith(Cast);
       CI->eraseFromParent();
       return Error::success();
@@ -295,6 +297,8 @@ class OpLowerer {
 
       removeResourceGlobals(CI);
 
+      DRM.updateResourceMap(CI, *OpBind);
+
       CI->replaceAllUsesWith(Cast);
       CI->eraseFromParent();
 
@@ -479,6 +483,9 @@ class OpLowerer {
           OpCode::BufferLoad, Args, CI->getName(), NewRetTy);
       if (Error E = OpCall.takeError())
         return E;
+
+      DRM.updateResUseMap(CI, *OpCall);
+
       if (Error E = replaceResRetUses(CI, *OpCall, HasCheckBit))
         return E;
 
@@ -547,6 +554,8 @@ class OpLowerer {
       if (Error E = OpCall.takeError())
         return E;
 
+      DRM.updateResUseMap(CI, *OpCall);
+
       CI->eraseFromParent();
       return Error::success();
     });
@@ -619,6 +628,193 @@ class OpLowerer {
     });
   }
 
+  Value *GenerateRawBufLd(Value *handle, Value *bufIdx, Value *offset, Type *Ty,
+                          IRBuilder<> &Builder, unsigned NumComponents,
+                          Constant *alignment) {
+    if (bufIdx == nullptr) {
+      // This is actually a byte address buffer load with a struct template
+      // type. The call takes only one coordinates for the offset.
+      bufIdx = offset;
+      offset = UndefValue::get(offset->getType());
+    }
+
+    // NumComponents 1: mask = 1  // Mask_X;
+    // NumComponents 2: mask = 3  // Mask_X | Mask_Y
+    // NumComponents 3: mask = 7  // Mask_X | Mask_Y | Mask_Z
+    // NumComponents 4: mask = 15 // Mask_X | Mask_Y | Mask_Z | Mask_W
+    assert((NumComponents) > 0 && (NumComponents < 5));
+    Constant *mask =
+        ConstantInt::get(Builder.getInt8Ty(), ((1 << NumComponents) - 1));
+
+    Value *Args[] = {handle, bufIdx, offset, mask, alignment};
+    Type *NewRetTy = OpBuilder.getResRetType(Ty->getScalarType());
+    Expected<CallInst *> OpCall = OpBuilder.tryCreateOp(
+        OpCode::RawBufferLoad, Args, "", NewRetTy); // TODO: Need name argument?
+    if (Error E = OpCall.takeError())
+      return nullptr;
+
+    return *OpCall;
+  }
+
+  void TranslateRawBufVecLd(Type *Ty, unsigned ElemCount, IRBuilder<> &Builder,
+                            Value *handle, Value *bufIdx, Value *baseOffset,
+                            const DataLayout &DL, std::vector<Value *> &bufLds,
+                            unsigned baseAlign, bool isScalarTy) {
+    Type *VecEltTy = Ty->getScalarType();
+
+    unsigned EltSize = DL.getTypeAllocSize(VecEltTy);
+    unsigned alignment = std::min(baseAlign, EltSize);
+    Constant *alignmentVal =
+        ConstantInt::get(M.getContext(), APInt(32, alignment));
+
+    if (baseOffset == nullptr) {
+      baseOffset = ConstantInt::get(Builder.getInt32Ty(), 0);
+    }
+
+    std::vector<Value *> elts(ElemCount);
+    unsigned rest = (ElemCount % 4);
+    for (unsigned i = 0; i < ElemCount - rest; i += 4) {
+      Value *bufLd = GenerateRawBufLd(handle, bufIdx, baseOffset, Ty, Builder,
+                                      4, alignmentVal);
+      bufLds.emplace_back(bufLd);
+
+      baseOffset = Builder.CreateAdd(
+          baseOffset, ConstantInt::get(Builder.getInt32Ty(), 4 * EltSize));
+    }
+
+    if (rest) {
+      Value *bufLd = GenerateRawBufLd(handle, bufIdx, baseOffset, Ty, Builder,
+                                      rest, alignmentVal);
+      bufLds.emplace_back(bufLd);
+    }
+  }
+
+  Error replaceMultiResRetsUses(CallInst *Intrin,
+                                std::vector<Value *> &bufLds) {
+    IRBuilder<> &IRB = OpBuilder.getIRB();
+
+    // TODO: HasCheckBit????
+
+    Type *OldTy = Intrin->getType();
+
+    // For scalars, we just extract the first element.
+    if (!isa<FixedVectorType>(OldTy)) {
+      CallInst *Op = dyn_cast<CallInst>(bufLds[0]);
+      assert(Op != nullptr);
+      Value *EVI = IRB.CreateExtractValue(Op, 0);
+
+      Intrin->replaceAllUsesWith(EVI);
+      DRM.updateResUseMap(Intrin, Op);
+      Intrin->eraseFromParent();
+
+      return Error::success();
+    }
+
+    const auto *VecTy = cast<FixedVectorType>(OldTy);
+    const unsigned N = VecTy->getNumElements();
+
+    std::vector<Value *> Extracts(N);
+
+    // The users of the operation should all be scalarized, so we attempt to
+    // replace the extractelements with extractvalues directly.
+    for (Use &U : make_early_inc_range(Intrin->uses())) {
+      if (auto *EEI = dyn_cast<ExtractElementInst>(U.getUser())) {
+        if (auto *IndexOp = dyn_cast<ConstantInt>(EEI->getIndexOperand())) {
+          size_t IndexVal = IndexOp->getZExtValue();
+          assert(IndexVal < N && "Index into buffer load out of range");
+          if (!Extracts[IndexVal]) {
+            CallInst *Op = dyn_cast<CallInst>(bufLds[IndexVal / 4]);
+            assert(Op != nullptr);
+            Extracts[IndexVal] = IRB.CreateExtractValue(Op, IndexVal % 4);
+          }
+          EEI->replaceAllUsesWith(Extracts[IndexVal]);
+          EEI->eraseFromParent();
+        } else {
+          // Need to handle DynamicAccesses here???
+        }
+      }
+    }
+
+    // If there's a dynamic access we need to round trip through stack memory so
+    // that we don't leave vectors around.
+    //
+    // TODO: dynamic access for rawbuffer??????
+    //
+
+    // If we still have uses, then we're not fully scalarized and need to
+    // recreate the vector. This should only happen for things like exported
+    // functions from libraries.
+    if (!Intrin->use_empty()) {
+      for (int I = 0, E = N; I != E; ++I)
+        if (!Extracts[I]) {
+          CallInst *Op = dyn_cast<CallInst>(bufLds[I / 4]);
+          assert(Op != nullptr);
+          Extracts[I] = IRB.CreateExtractValue(Op, I % 4);
+        }
+
+      Value *Vec = UndefValue::get(OldTy);
+      for (int I = 0, E = N; I != E; ++I)
+        Vec = IRB.CreateInsertElement(Vec, Extracts[I], I);
+
+      Intrin->replaceAllUsesWith(Vec);
+    }
+
+    // TODO:
+    // Remove the dx.op.rawbufferload without any uses now?
+
+    DRM.updateResUseMap(Intrin, bufLds);
+    Intrin->eraseFromParent();
+
+    return Error::success();
+  }
+
+  [[nodiscard]] bool lowerRawBufferLoad(Function &F) {
+    IRBuilder<> &IRB = OpBuilder.getIRB();
+
+    return replaceFunction(F, [&](CallInst *CI) -> Error {
+      IRB.SetInsertPoint(CI);
+
+      auto *It = DRM.find(DRM.findResHandleByUse(CI));
+      assert(It != DRM.end() && "Resource not in map?");
+      dxil::ResourceInfo &RI = *It;
+
+      ResourceKind RCKind =  RI.getResourceKind();
+      assert((RCKind == dxil::ResourceKind::StructuredBuffer) ||
+             (RCKind == dxil::ResourceKind::RawBuffer));
+
+      Type *Ty = CI->getType();
+      std::vector<Value *> bufLds;
+      // TODO: Need check Bool type load???
+
+      unsigned numComponents = 1;
+      if (Ty->isVectorTy()) {
+        numComponents = dyn_cast<FixedVectorType>(Ty)->getNumElements();
+      }
+
+      Value *Handle =
+          createTmpHandleCast(CI->getArgOperand(0), OpBuilder.getHandleType());
+      Value *bufIdx = CI->getArgOperand(1);
+      Value *baseOffset = CI->getArgOperand(2);
+
+      bool isScalarTy = !Ty->isVectorTy();
+
+      if (RCKind == dxil::ResourceKind::StructuredBuffer) {
+        TranslateRawBufVecLd(Ty, numComponents, IRB, Handle, bufIdx, baseOffset,
+                             F.getDataLayout(), bufLds,
+                             /*baseAlign (in bytes)*/ 8, isScalarTy);
+      } else {
+        TranslateRawBufVecLd(Ty, numComponents, IRB, Handle, bufIdx, baseOffset,
+                             F.getDataLayout(), bufLds,
+                             /*baseAlign (in bytes)*/ 4, isScalarTy);
+      }
+
+      if (Error E = replaceMultiResRetsUses(CI, bufLds))
+        return E;
+
+      return Error::success();
+    });
+  }
+
   bool lowerIntrinsics() {
     bool Updated = false;
     bool HasErrors = false;
@@ -638,6 +834,9 @@ class OpLowerer {
       case Intrinsic::dx_handle_fromBinding:
         HasErrors |= lowerHandleFromBinding(F);
         break;
+      case Intrinsic::dx_rawBufferLoad:
+        HasErrors |= lowerRawBufferLoad(F);
+        break;
       case Intrinsic::dx_typedBufferLoad:
         HasErrors |= lowerTypedBufferLoad(F, /*HasCheckBit=*/false);
         break;
diff --git a/llvm/test/Analysis/DXILResource/resource-map.ll b/llvm/test/Analysis/DXILResource/resource-map.ll
new file mode 100644
index 00000000000000..65255d4c942e53
--- /dev/null
+++ b/llvm/test/Analysis/DXILResource/resource-map.ll
@@ -0,0 +1,36 @@
+; RUN: opt -S -disable-output -disable-output -passes="print<dxil-resource>" < %s 2>&1 | FileCheck %s
+
+define void @test_typedbuffer() {
+  ; RWBuffer<float4> Buf : register(u5, space3)
+  %uav1 = call target("dx.TypedBuffer", <4 x float>, 1, 0, 0)
+              @llvm.dx.handle.fromBinding.tdx.TypedBuffer_f32_1_0(
+                  i32 3, i32 5, i32 1, i32 0, i1 false)
+  ; CHECK: Binding [[UAV1:[0-9]+]]:
+  ; CHECK:   Symbol: ptr undef
+  ; CHECK:   Name: ""
+  ; CHECK:   Binding:
+  ; CHECK:     Record ID: 0
+  ; CHECK:     Space: 3
+  ; CHECK:     Lower Bound: 5
+  ; CHECK:     Size: 1
+  ; CHECK:   Class: UAV
+  ; CHECK:   Kind: TypedBuffer
+  ; CHECK:   Globally Coherent: 0
+  ; CHECK:   HasCounter: 0
+  ; CHECK:   IsROV: 0
+  ; CHECK:   Element Type: f32
+  ; CHECK:   Element Count: 4
+
+  ; CHECK:     Call bound to [[UAV1]]:  %uav1 = call target("dx.TypedBuffer", <4 x float>, 1, 0, 0) @llvm.dx.handle.fromBinding.tdx.TypedBuffer_v4f32_1_0_0t(i32 3, i32 5, i32 1, i32 0, i1 false)
+  ; CHECK-DAG: Resource [[UAV1]] is used by   %data0 = call <4 x float> @llvm.dx.typedBufferLoad.v4f32.tdx.TypedBuffer_v4f32_1_0_0t(target("dx.TypedBuffer", <4 x float>, 1, 0, 0) %uav1, i32 0)
+  ; CHECK-DAG: Resource [[UAV1]] is used by   call void @llvm.dx.typedBufferStore.tdx.TypedBuffer_v4f32_1_0_0t.v4f32(target("dx.TypedBuffer", <4 x float>, 1, 0, 0) %uav1, i32 2, <4 x float> %data0)
+
+  %data0 = call <4 x float> @llvm.dx.typedBufferLoad(
+      target("dx.TypedBuffer", <4 x float>, 1, 0, 0) %uav1, i32 0)
+  call void @llvm.dx.typedBufferStore(
+      target("dx.TypedBuffer", <4 x float>, 1, 0, 0) %uav1,
+      i32 2, <4 x float> %data0)
+
+  ret void
+}
+
diff --git a/llvm/test/CodeGen/DirectX/DXILResource/dxil-resource-map.ll b/llvm/test/CodeGen/DirectX/DXILResource/dxil-resource-map.ll
new file mode 100644
index 00000000000000..ac5f3d16145974
--- /dev/null
+++ b/llvm/test/CodeGen/DirectX/DXILResource/dxil-resource-map.ll
@@ -0,0 +1,48 @@
+; RUN: opt -S -disable-output -disable-output -passes="print<dxil-resource>,dxil-op-lower,print<dxil-resource>" -mtriple=dxil-pc-shadermodel6.6-compute < %s 2>&1 | FileCheck %s -check-prefixes=CHECK,CHECK_SM66
+; RUN: opt -S -disable-output -disable-output -passes="print<dxil-resource>,dxil-op-lower,print<dxil-resource>" -mtriple=dxil-pc-shadermodel6.2-compute < %s 2>&1 | FileCheck %s -check-prefixes=CHECK,CHECK_SM62
+
+define void @test_typedbuffer() {
+  ; RWBuffer<float4> Buf : register(u5, space3)
+  %uav1 = call target("dx.TypedBuffer", <4 x float>, 1, 0, 0)
+              @llvm.dx.handle.fromBinding.tdx.TypedBuffer_f32_1_0(
+                  i32 3, i32 5, i32 1, i32 0, i1 false)
+  ; CHECK: Binding [[UAV1:[0-9]+]]:
+  ; CHECK:   Symbol: ptr undef
+  ; CHECK:   Name: ""
+  ; CHECK:   Binding:
+  ; CHECK:     Record ID: 0
+  ; CHECK:     Space: 3
+  ; CHECK:     Lower Bound: 5
+  ; CHECK:     Size: 1
+  ; CHECK:   Class: UAV
+  ; CHECK:   Kind: TypedBuffer
+  ; CHECK:   Globally Coherent: 0
+  ; CHECK:   HasCounter: 0
+  ; CHECK:   IsROV: 0
+  ; CHECK:   Element Type: f32
+  ; CHECK:   Element Count: 4
+
+  ; CHECK:     Call bound to [[UAV1]]:  %uav1 = call target("dx.TypedBuffer", <4 x float>, 1, 0, 0) @llvm.dx.handle.fromBinding.tdx.TypedBuffer_v4f32_1_0_0t(i32 3, i32 5, i32 1, i32 0, i1 false)
+  ; CHECK-DAG: Resource [[UAV1]] is used by   %data0 = call <4 x float> @llvm.dx.typedBufferLoad.v4f32.tdx.TypedBuffer_v4f32_1_0_0t(target("dx.TypedBuffer", <4 x float>, 1, 0, 0) %uav1, i32 0)
+  ; CHECK-DAG: Resource [[UAV1]] is used by   call void @llvm.dx.typedBufferStore.tdx.TypedBuffer_v4f32_1_0_0t.v4f32(target("dx.TypedBuffer", <4 x float>, 1, 0, 0) %uav1, i32 2, <4 x float> %data0)
+
+  %data0 = call <4 x float> @llvm.dx.typedBufferLoad(
+      target("dx.TypedBuffer", <4 x float>, 1, 0, 0) %uav1, i32 0)
+  call void @llvm.dx.typedBufferStore(
+      target("dx.TypedBuffer", <4 x float>, 1, 0, 0) %uav1,
+      i32 2, <4 x float> %data0)
+
+  ;
+  ;;; After dxil-op-lower, the DXILResourceMap info should be updated.
+  ;
+  ; CHECK_SM66:     Call bound to [[UAV1]]:  %uav11 = call %dx.types.Handle @dx.op.createHandleFromBinding(i32 217, %dx.types.ResBind { i32 5, i32 5, i32 3, i8 1 }, i32 0, i1 false)
+  ; CHECK_SM66-DAG: Resource [[UAV1]] is used by   %data02 = call %dx.types.ResRet.f32 @dx.op.bufferLoad.f32(i32 68, %dx.types.Handle %uav1_annot, i32 0, i32 undef)
+  ; CHECK_SM66-DAG: Resource [[UAV1]] is used by   call void @dx.op.bufferStore.f32(i32 69, %dx.types.Handle %uav1_annot, i32 2, i32 undef, float %9, float %10, float %11, float %12, i8 1...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/116845


More information about the llvm-commits mailing list