Skip to content

Lower llvm.dx.rawBufferLoad to dxil ops #116845

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Conversation

lizhengxing
Copy link
Contributor

@lizhengxing lizhengxing commented Nov 19, 2024

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](8e1bca0)
The Raw Buffer Load change: [Lower llvm.dx.rawbufferload to dxil ops · lizhengxing/llvm-project@731703f](27c361b)

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](3a8f3a1)

When lowering some resource use intrisics to DXIL operations, it needs to know the information of the resource that the intrisics are using.

This PR adds Resource uses to Resource Handle map in DXILResourceMap. It helps the resource uses to find the resource information.

This PR is also useful to llvm#106188
This PR lowers the @llvm.dx.rawBufferLoad intrinsic to @dx.op.rawBufferLoad
@lizhengxing lizhengxing changed the title Dx lower to rawbufferload dxil ops draft rebase Dx lower to rawbufferload dxil ops draft PR Nov 19, 2024
Copy link

⚠️ C/C++ code formatter, clang-format found issues in your code. ⚠️

You can test this locally with the following command:
git-clang-format --diff cd418030de7ae75750bc4e48d1238baf03c675e5 3a8f3a1996ed2c87aae08632fcb4fc08893cfae1 --extensions h,cpp -- llvm/include/llvm/Analysis/DXILResource.h llvm/lib/Analysis/DXILResource.cpp llvm/lib/Target/DirectX/DXILOpLowering.cpp
View the diff from clang-format here.
diff --git a/llvm/lib/Analysis/DXILResource.cpp b/llvm/lib/Analysis/DXILResource.cpp
index be4fad8a84..ed9644bff0 100644
--- a/llvm/lib/Analysis/DXILResource.cpp
+++ b/llvm/lib/Analysis/DXILResource.cpp
@@ -791,19 +791,18 @@ void DXILResourceMap::updateResourceMap(CallInst *origCallInst,
   }
 }
 
-  void DXILResourceMap::updateResUseMap(CallInst *origResUse,
+void DXILResourceMap::updateResUseMap(CallInst *origResUse,
                                       std::vector<Value *> &multiNewResUse) {
-    assert((origResUse != nullptr) && "Wrong Inputs");
+  assert((origResUse != nullptr) && "Wrong Inputs");
 
-    for (int i = 0; i < multiNewResUse.size(); ++i) {
-      CallInst *newResUse = dyn_cast<CallInst>(multiNewResUse[i]);
-      assert(newResUse != nullptr);
+  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);
-    }
+    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) {
diff --git a/llvm/lib/Target/DirectX/DXILOpLowering.cpp b/llvm/lib/Target/DirectX/DXILOpLowering.cpp
index d2b6f05fc9..a8c8b8c870 100644
--- a/llvm/lib/Target/DirectX/DXILOpLowering.cpp
+++ b/llvm/lib/Target/DirectX/DXILOpLowering.cpp
@@ -778,7 +778,7 @@ public:
       assert(It != DRM.end() && "Resource not in map?");
       dxil::ResourceInfo &RI = *It;
 
-      ResourceKind RCKind =  RI.getResourceKind();
+      ResourceKind RCKind = RI.getResourceKind();
       assert((RCKind == dxil::ResourceKind::StructuredBuffer) ||
              (RCKind == dxil::ResourceKind::RawBuffer));
 

@lizhengxing lizhengxing changed the title Dx lower to rawbufferload dxil ops draft PR Lower llvm.dx.rawBufferLoad to dxil ops Nov 19, 2024
@lizhengxing lizhengxing marked this pull request as ready for review November 19, 2024 18:31
@llvmbot llvmbot added backend:DirectX llvm:ir llvm:analysis Includes value tracking, cost tables and constant folding labels Nov 19, 2024
@llvmbot
Copy link
Member

llvmbot commented Nov 19, 2024

@llvm/pr-subscribers-backend-directx
@llvm/pr-subscribers-llvm-ir

@llvm/pr-subscribers-llvm-analysis

Author: Zhengxing li (lizhengxing)

Changes

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](8e1bca0)
The Raw Buffer Load change: [Lower llvm.dx.rawbufferload to dxil ops · lizhengxing/llvm-project@731703f](27c361b)

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](3a8f3a1)


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 --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]

@damyanp
Copy link
Contributor

damyanp commented Dec 10, 2024

@lizhengxing - looks like there's some conflicts that need resolving before completing this. The description mentions it is a draft. Is this PR still something you want us to review and take in?

@lizhengxing
Copy link
Contributor Author

@lizhengxing - looks like there's some conflicts that need resolving before completing this. The description mentions it is a draft. Is this PR still something you want us to review and take in?

No, there's no review needed for this draft PR. I'll re-work the PR based on Justin's feedback.

@damyanp
Copy link
Contributor

damyanp commented Dec 10, 2024

No, there's no review needed for this draft PR

Should we convert it to draft then?

@lizhengxing lizhengxing marked this pull request as draft December 11, 2024 16:49
@lizhengxing
Copy link
Contributor Author

No, there's no review needed for this draft PR

Should we convert it to draft then?

Done. Converted it to draft.

@bogner
Copy link
Contributor

bogner commented Dec 23, 2024

I think this is superceded by #121012. Sorry to step on your toes here but things changed somewhat significantly in the area.

@lizhengxing
Copy link
Contributor Author

As @bogner mentioned in the latest comment, things changed a lot in the area.

@lizhengxing lizhengxing closed this Jan 3, 2025
@lizhengxing lizhengxing deleted the dx-lower-to-rawbufferload-dxil-ops-draft-rebase branch January 3, 2025 19:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
backend:DirectX llvm:analysis Includes value tracking, cost tables and constant folding llvm:ir
Projects
Archived in project
Development

Successfully merging this pull request may close these issues.

4 participants