Parcourir la source

Add GetResourceFromHeap. (#2691)

Add GetResourceFromHeap for hlsl.
For Dxil, add CreateHandleFromHeap and AnnotateHandle.

All handles ( createHandle, createHandleForLib, createHandleFromHeap ) must be annotated with AnnotateHandle before use.

TODO: add AnnotateHandle for pix passes.
            cleanup code about resource.
Xiang Li il y a 5 ans
Parent
commit
91fe12f0eb
51 fichiers modifiés avec 1603 ajouts et 508 suppressions
  1. 2 0
      docs/DXIL.rst
  2. 46 3
      include/dxc/DXIL/DxilConstants.h
  3. 63 0
      include/dxc/DXIL/DxilInstructions.h
  4. 2 0
      include/dxc/DXIL/DxilOperations.h
  5. 73 0
      include/dxc/DXIL/DxilResourceProperties.h
  6. 2 0
      include/dxc/DXIL/DxilUtil.h
  7. 2 0
      include/dxc/HLSL/HLModule.h
  8. 9 0
      include/dxc/HLSL/HLOperations.h
  9. 1 0
      include/dxc/HlslIntrinsicOp.h
  10. 2 2
      include/dxc/dxcapi.internal.h
  11. 1 0
      lib/DXIL/CMakeLists.txt
  12. 1 0
      lib/DXIL/DxilModule.cpp
  13. 25 1
      lib/DXIL/DxilOperations.cpp
  14. 10 1
      lib/DXIL/DxilResource.cpp
  15. 1 1
      lib/DXIL/DxilResourceBase.cpp
  16. 199 0
      lib/DXIL/DxilResourceProperties.cpp
  17. 24 24
      lib/DXIL/DxilShaderFlags.cpp
  18. 35 0
      lib/DXIL/DxilUtil.cpp
  19. 7 1
      lib/HLSL/DxilCondenseResources.cpp
  20. 7 2
      lib/HLSL/DxilContainerReflection.cpp
  21. 280 3
      lib/HLSL/DxilGenerationPass.cpp
  22. 1 1
      lib/HLSL/DxilPatchShaderRecordBindings.cpp
  23. 18 0
      lib/HLSL/DxilPreparePasses.cpp
  24. 1 178
      lib/HLSL/DxilTranslateRawBuffer.cpp
  25. 112 99
      lib/HLSL/DxilValidation.cpp
  26. 6 0
      lib/HLSL/HLModule.cpp
  27. 59 4
      lib/HLSL/HLOperationLower.cpp
  28. 10 0
      lib/HLSL/HLOperations.cpp
  29. 2 0
      tools/clang/include/clang/AST/HlslTypes.h
  30. 2 1
      tools/clang/include/clang/AST/Type.h
  31. 4 4
      tools/clang/include/clang/Sema/SemaHLSL.h
  32. 12 0
      tools/clang/lib/AST/ASTContextHLSL.cpp
  33. 14 0
      tools/clang/lib/AST/HlslTypes.cpp
  34. 2 0
      tools/clang/lib/AST/Type.cpp
  35. 3 0
      tools/clang/lib/AST/TypePrinter.cpp
  36. 3 0
      tools/clang/lib/CodeGen/CGCall.cpp
  37. 295 20
      tools/clang/lib/CodeGen/CGHLSLMS.cpp
  38. 2 0
      tools/clang/lib/CodeGen/CGHLSLRuntime.h
  39. 39 13
      tools/clang/lib/Sema/SemaHLSL.cpp
  40. 20 1
      tools/clang/lib/Sema/SemaType.cpp
  41. 141 135
      tools/clang/lib/Sema/gen_intrin_main_tables_15.h
  42. 1 1
      tools/clang/test/HLSLFileCheck/dxil/debug/value_cache/load.hlsl
  43. 1 1
      tools/clang/test/HLSLFileCheck/dxil/debug/value_cache/resource_array.hlsl
  44. 1 2
      tools/clang/test/HLSLFileCheck/dxil/debug/value_cache/right_branch.hlsl
  45. 0 9
      tools/clang/test/HLSLFileCheck/hlsl/intrinsics/basic/abs1.hlsl
  46. 9 0
      tools/clang/test/HLSLFileCheck/hlsl/intrinsics/createHandleFromHeap/createFromHeap.hlsl
  47. 24 0
      tools/clang/test/HLSLFileCheck/hlsl/intrinsics/createHandleFromHeap/createFromHeap2.hlsl
  48. 5 1
      tools/clang/tools/dxcompiler/dxcdisassembler.cpp
  49. 2 0
      utils/hct/gen_intrin_main.txt
  50. 21 0
      utils/hct/hctdb.py
  51. 1 0
      utils/hct/hctdb_instrhelp.py

+ 2 - 0
docs/DXIL.rst

@@ -2311,6 +2311,8 @@ ID  Name                                                  Description
 213 GeometryIndex                                         The autogenerated index of the current geometry in the bottom-level structure
 214 RayQuery_CandidateInstanceContributionToHitGroupIndex returns candidate hit InstanceContributionToHitGroupIndex
 215 RayQuery_CommittedInstanceContributionToHitGroupIndex returns committed hit InstanceContributionToHitGroupIndex
+216 CreateHandleFromHeap                                  create resource handle from heap
+217 AnnotateHandle                                        annotate handle with resource properties
 === ===================================================== =======================================================================================================================================================================================================================
 
 

+ 46 - 3
include/dxc/DXIL/DxilConstants.h

@@ -115,7 +115,7 @@ namespace DXIL {
 
   const unsigned kResRetStatusIndex = 4;
 
-  enum class ComponentType : uint8_t { 
+  enum class ComponentType : uint32_t {
     Invalid = 0,
     I1, I16, U16, I32, U32, I64, U64,
     F16, F32, F64,
@@ -330,9 +330,42 @@ namespace DXIL {
     RTAccelerationStructure,
     FeedbackTexture2D,
     FeedbackTexture2DArray,
+    StructuredBufferWithCounter,
+    SamplerComparison,
     NumEntries,
   };
 
+  inline bool IsAnyTexture(DXIL::ResourceKind ResourceKind) {
+    return DXIL::ResourceKind::Texture1D <= ResourceKind &&
+           ResourceKind <= DXIL::ResourceKind::TextureCubeArray;
+  }
+
+  inline bool IsStructuredBuffer(DXIL::ResourceKind ResourceKind) {
+    return ResourceKind == DXIL::ResourceKind::StructuredBuffer ||
+           ResourceKind == DXIL::ResourceKind::StructuredBufferWithCounter;
+  }
+
+  inline bool IsTypedBuffer(DXIL::ResourceKind ResourceKind) {
+    return ResourceKind == DXIL::ResourceKind::TypedBuffer;
+  }
+
+  inline bool IsTyped(DXIL::ResourceKind ResourceKind) {
+    return IsTypedBuffer(ResourceKind) || IsAnyTexture(ResourceKind);
+  }
+
+  inline bool IsRawBuffer(DXIL::ResourceKind ResourceKind) {
+    return ResourceKind == DXIL::ResourceKind::RawBuffer;
+  }
+
+  inline bool IsTBuffer(DXIL::ResourceKind ResourceKind) {
+    return ResourceKind == DXIL::ResourceKind::TBuffer;
+  }
+
+  inline bool IsFeedbackTexture(DXIL::ResourceKind ResourceKind) {
+    return ResourceKind == DXIL::ResourceKind::FeedbackTexture2D ||
+           ResourceKind == DXIL::ResourceKind::FeedbackTexture2DArray;
+  }
+
   // TODO: change opcodes.
   /* <py::lines('OPCODE-ENUM')>hctdb_instrhelp.get_enum_decl("OpCode")</py>*/
   // OPCODE-ENUM:BEGIN
@@ -412,6 +445,10 @@ namespace DXIL {
     EmitThenCutStream = 99, // equivalent to an EmitStream followed by a CutStream
     GSInstanceID = 100, // GSInstanceID
   
+    // Get handle from heap
+    AnnotateHandle = 217, // annotate handle with resource properties
+    CreateHandleFromHeap = 216, // create resource handle from heap
+  
     // Graphics shader
     ViewID = 138, // returns the view index
   
@@ -662,8 +699,9 @@ namespace DXIL {
     NumOpCodes_Dxil_1_3 = 162,
     NumOpCodes_Dxil_1_4 = 165,
     NumOpCodes_Dxil_1_5 = 216,
+    NumOpCodes_Dxil_1_6 = 218,
   
-    NumOpCodes = 216 // exclusive last value of enumeration
+    NumOpCodes = 218 // exclusive last value of enumeration
   };
   // OPCODE-ENUM:END
 
@@ -730,6 +768,10 @@ namespace DXIL {
     EmitThenCutStream,
     GSInstanceID,
   
+    // Get handle from heap
+    AnnotateHandle,
+    CreateHandleFromHeap,
+  
     // Graphics shader
     ViewID,
   
@@ -910,8 +952,9 @@ namespace DXIL {
     NumOpClasses_Dxil_1_3 = 118,
     NumOpClasses_Dxil_1_4 = 120,
     NumOpClasses_Dxil_1_5 = 143,
+    NumOpClasses_Dxil_1_6 = 145,
   
-    NumOpClasses = 143 // exclusive last value of enumeration
+    NumOpClasses = 145 // exclusive last value of enumeration
   };
   // OPCODECLASS-ENUM:END
 

+ 63 - 0
include/dxc/DXIL/DxilInstructions.h

@@ -6987,5 +6987,68 @@ struct DxilInst_RayQuery_CommittedInstanceContributionToHitGroupIndex {
   llvm::Value *get_rayQueryHandle() const { return Instr->getOperand(1); }
   void set_rayQueryHandle(llvm::Value *val) { Instr->setOperand(1, val); }
 };
+
+/// This instruction create resource handle from heap
+struct DxilInst_CreateHandleFromHeap {
+  llvm::Instruction *Instr;
+  // Construction and identification
+  DxilInst_CreateHandleFromHeap(llvm::Instruction *pInstr) : Instr(pInstr) {}
+  operator bool() const {
+    return hlsl::OP::IsDxilOpFuncCallInst(Instr, hlsl::OP::OpCode::CreateHandleFromHeap);
+  }
+  // Validation support
+  bool isAllowed() const { return true; }
+  bool isArgumentListValid() const {
+    if (2 != llvm::dyn_cast<llvm::CallInst>(Instr)->getNumArgOperands()) return false;
+    return true;
+  }
+  // Metadata
+  bool requiresUniformInputs() const { return false; }
+  // Operand indexes
+  enum OperandIdx {
+    arg_index = 1,
+  };
+  // Accessors
+  llvm::Value *get_index() const { return Instr->getOperand(1); }
+  void set_index(llvm::Value *val) { Instr->setOperand(1, val); }
+};
+
+/// This instruction annotate handle with resource properties
+struct DxilInst_AnnotateHandle {
+  llvm::Instruction *Instr;
+  // Construction and identification
+  DxilInst_AnnotateHandle(llvm::Instruction *pInstr) : Instr(pInstr) {}
+  operator bool() const {
+    return hlsl::OP::IsDxilOpFuncCallInst(Instr, hlsl::OP::OpCode::AnnotateHandle);
+  }
+  // Validation support
+  bool isAllowed() const { return true; }
+  bool isArgumentListValid() const {
+    if (5 != llvm::dyn_cast<llvm::CallInst>(Instr)->getNumArgOperands()) return false;
+    return true;
+  }
+  // Metadata
+  bool requiresUniformInputs() const { return false; }
+  // Operand indexes
+  enum OperandIdx {
+    arg_res = 1,
+    arg_resourceClass = 2,
+    arg_resourceKind = 3,
+    arg_props = 4,
+  };
+  // Accessors
+  llvm::Value *get_res() const { return Instr->getOperand(1); }
+  void set_res(llvm::Value *val) { Instr->setOperand(1, val); }
+  llvm::Value *get_resourceClass() const { return Instr->getOperand(2); }
+  void set_resourceClass(llvm::Value *val) { Instr->setOperand(2, val); }
+  int8_t get_resourceClass_val() const { return (int8_t)(llvm::dyn_cast<llvm::ConstantInt>(Instr->getOperand(2))->getZExtValue()); }
+  void set_resourceClass_val(int8_t val) { Instr->setOperand(2, llvm::Constant::getIntegerValue(llvm::IntegerType::get(Instr->getContext(), 8), llvm::APInt(8, (uint64_t)val))); }
+  llvm::Value *get_resourceKind() const { return Instr->getOperand(3); }
+  void set_resourceKind(llvm::Value *val) { Instr->setOperand(3, val); }
+  int8_t get_resourceKind_val() const { return (int8_t)(llvm::dyn_cast<llvm::ConstantInt>(Instr->getOperand(3))->getZExtValue()); }
+  void set_resourceKind_val(int8_t val) { Instr->setOperand(3, llvm::Constant::getIntegerValue(llvm::IntegerType::get(Instr->getContext(), 8), llvm::APInt(8, (uint64_t)val))); }
+  llvm::Value *get_props() const { return Instr->getOperand(4); }
+  void set_props(llvm::Value *val) { Instr->setOperand(4, val); }
+};
 // INSTR-HELPER:END
 } // namespace hlsl

+ 2 - 0
include/dxc/DXIL/DxilOperations.h

@@ -49,6 +49,7 @@ public:
   llvm::Type *GetOverloadType(OpCode OpCode, llvm::Function *F);
   llvm::LLVMContext &GetCtx() { return m_Ctx; }
   llvm::Type *GetHandleType() const;
+  llvm::Type *GetResourcePropertiesType() const;
   llvm::Type *GetDimensionsType() const;
   llvm::Type *GetSamplePosType() const;
   llvm::Type *GetBinaryWithCarryType() const;
@@ -119,6 +120,7 @@ private:
   llvm::Module *m_pModule;
 
   llvm::Type *m_pHandleType;
+  llvm::Type *m_pResourcePropertiesType;
   llvm::Type *m_pDimensionsType;
   llvm::Type *m_pSamplePosType;
   llvm::Type *m_pBinaryWithCarryType;

+ 73 - 0
include/dxc/DXIL/DxilResourceProperties.h

@@ -0,0 +1,73 @@
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// DxilHandleAnnotation.h                                                    //
+// Copyright (C) Microsoft Corporation. All rights reserved.                 //
+// This file is distributed under the University of Illinois Open Source     //
+// License. See LICENSE.TXT for details.                                     //
+//                                                                           //
+// Representation properties for DXIL handle.                                //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+#pragma once
+
+#include "DxilConstants.h"
+
+namespace llvm {
+class Constant;
+class Type;
+}
+
+namespace hlsl {
+
+struct DxilResourceProperties {
+  DXIL::ResourceClass Class;
+  DXIL::ResourceKind  Kind;
+  static constexpr unsigned kSampleCountUndefined = 0x7;
+
+  union {
+    struct {
+      DXIL::ComponentType CompType : 5; // TypedBuffer/Image.
+      uint32_t SingleComponent : 1;     // Return type is single component.
+      // 2^SampleCountPow2 for Sample count of Texture2DMS.
+      uint32_t SampleCountPow2 : 3;
+      uint32_t Reserved : 23;
+    } Typed;
+    uint32_t ElementStride; // in bytes for StructurizedBuffer.
+    DXIL::SamplerFeedbackType SamplerFeedbackType; // FeedbackTexture2D.
+    uint32_t SizeInBytes; // Cbuffer instance size in bytes.
+    uint32_t RawDword0;
+  };
+
+  union {
+    struct {
+      uint32_t bROV : 1;              // UAV
+      uint32_t bGloballyCoherent : 1; // UAV
+      uint32_t Reserved : 30;
+    } UAV;
+    uint32_t RawDword1;
+  };
+
+  bool operator==(const DxilResourceProperties &);
+  bool operator!=(const DxilResourceProperties &);
+};
+
+static_assert(sizeof(DxilResourceProperties) == 4 * sizeof(uint32_t),
+              "update shader model and functions read/write "
+              "DxilResourceProperties when size is changed");
+
+class ShaderModel;
+class DxilResourceBase;
+struct DxilInst_AnnotateHandle;
+
+namespace resource_helper {
+llvm::Constant *getAsConstant(const DxilResourceProperties &, llvm::Type *Ty,
+                              const ShaderModel &);
+DxilResourceProperties
+loadFromAnnotateHandle(DxilInst_AnnotateHandle &annotateHandle, llvm::Type *Ty,
+                       const ShaderModel &);
+DxilResourceProperties loadFromResourceBase(DxilResourceBase *);
+
+}; // namespace resource_helper
+
+} // namespace hlsl

+ 2 - 0
include/dxc/DXIL/DxilUtil.h

@@ -113,6 +113,8 @@ namespace dxilutil {
   bool IsHLSLResourceType(llvm::Type *Ty);
   bool IsHLSLObjectType(llvm::Type *Ty);
   bool IsHLSLRayQueryType(llvm::Type *Ty);
+  bool IsHLSLResourceDescType(llvm::Type *Ty);
+  bool IsResourceSingleComponent(llvm::Type *Ty);
   bool IsSplat(llvm::ConstantDataVector *cdv);
 
   llvm::Type* StripArrayTypes(llvm::Type *Ty, llvm::SmallVectorImpl<unsigned> *OuterToInnerLengths = nullptr);

+ 2 - 0
include/dxc/HLSL/HLModule.h

@@ -179,6 +179,8 @@ public:
   llvm::MDNode *DxilUAVToMDNode(const DxilResource &UAV);
   llvm::MDNode *DxilCBufferToMDNode(const DxilCBuffer &CB);
   void LoadDxilResourceBaseFromMDNode(llvm::MDNode *MD, DxilResourceBase &R);
+  void LoadDxilResourceFromMDNode(llvm::MDNode *MD, DxilResource &R);
+  void LoadDxilSamplerFromMDNode(llvm::MDNode *MD, DxilSampler &S);
   DxilResourceBase *AddResourceWithGlobalVariableAndMDNode(llvm::Constant *GV,
                                                            llvm::MDNode *MD);
   unsigned GetBindingForResourceInCB(llvm::GetElementPtrInst *CbPtr,

+ 9 - 0
include/dxc/HLSL/HLOperations.h

@@ -36,6 +36,7 @@ enum class HLOpcodeGroup {
   HLMatLoadStore,
   HLSelect,
   HLCreateHandle,
+  HLAnnotateHandle,
   NumOfHLOps
 };
 
@@ -346,6 +347,14 @@ const unsigned kWaveAllEqualValueOpIdx = 1;
 const unsigned kCreateHandleResourceOpIdx = 1;
 const unsigned kCreateHandleIndexOpIdx = 2; // Only for array of cbuffer.
 
+// AnnotateHandle.
+const unsigned kAnnotateHandleHandleOpIdx = 1;
+const unsigned kAnnotateHandleResourceClassOpIdx = 2;
+const unsigned kAnnotateHandleResourceKindOpIdx = 3;
+const unsigned kAnnotateHandleResourcePropertiesOpIdx = 4;
+const unsigned kAnnotateHandleResourceTypeOpIdx = 5;
+
+
 // TraceRay.
 const unsigned kTraceRayRayDescOpIdx = 7;
 const unsigned kTraceRayPayLoadOpIdx = 8;

+ 1 - 0
include/dxc/HlslIntrinsicOp.h

@@ -41,6 +41,7 @@ import hctdb_instrhelp
   IOP_GetAttributeAtVertex,
   IOP_GetRenderTargetSampleCount,
   IOP_GetRenderTargetSamplePosition,
+  IOP_GetResourceFromHeap,
   IOP_GroupMemoryBarrier,
   IOP_GroupMemoryBarrierWithGroupSync,
   IOP_HitKind,

+ 2 - 2
include/dxc/dxcapi.internal.h

@@ -89,8 +89,8 @@ enum LEGAL_INTRINSIC_COMPTYPES {
 
   LICOMPTYPE_TEXTURE2D = 33,
   LICOMPTYPE_TEXTURE2DARRAY = 34,
-
-  LICOMPTYPE_COUNT = 35
+  LICOMPTYPE_RESOURCE = 35,
+  LICOMPTYPE_COUNT = 36
 };
 
 static const BYTE IA_SPECIAL_BASE = 0xf0;

+ 1 - 0
lib/DXIL/CMakeLists.txt

@@ -9,6 +9,7 @@ add_llvm_library(LLVMDXIL
   DxilOperations.cpp
   DxilResource.cpp
   DxilResourceBase.cpp
+  DxilResourceProperties.cpp
   DxilSampler.cpp
   DxilSemantic.cpp
   DxilShaderFlags.cpp

+ 1 - 0
lib/DXIL/DxilModule.cpp

@@ -315,6 +315,7 @@ void DxilModule::CollectShaderFlagsForModule(ShaderFlags &Flags) {
     switch (UAV->GetKind()) {
     case DXIL::ResourceKind::RawBuffer:
     case DXIL::ResourceKind::StructuredBuffer:
+    case DXIL::ResourceKind::StructuredBufferWithCounter:
       hasRawAndStructuredBuffer = true;
       break;
     default:

+ 25 - 1
lib/DXIL/DxilOperations.cpp

@@ -384,6 +384,10 @@ const OP::OpCodeProperty OP::m_OpCodeProps[(unsigned)OP::OpCode::NumOpCodes] = {
   // Inline Ray Query                                                                                                        void,     h,     f,     d,    i1,    i8,   i16,   i32,   i64,   udt,   obj ,  function attribute
   {  OC::RayQuery_CandidateInstanceContributionToHitGroupIndex, "RayQuery_CandidateInstanceContributionToHitGroupIndex", OCC::RayQuery_StateScalar,     "rayQuery_StateScalar",      { false, false, false, false, false, false, false,  true, false, false, false}, Attribute::ReadOnly, },
   {  OC::RayQuery_CommittedInstanceContributionToHitGroupIndex, "RayQuery_CommittedInstanceContributionToHitGroupIndex", OCC::RayQuery_StateScalar,     "rayQuery_StateScalar",      { false, false, false, false, false, false, false,  true, false, false, false}, Attribute::ReadOnly, },
+
+  // Get handle from heap                                                                                                    void,     h,     f,     d,    i1,    i8,   i16,   i32,   i64,   udt,   obj ,  function attribute
+  {  OC::CreateHandleFromHeap,    "CreateHandleFromHeap",     OCC::CreateHandleFromHeap,     "createHandleFromHeap",      {  true, false, false, false, false, false, false, false, false, false, false}, Attribute::ReadOnly, },
+  {  OC::AnnotateHandle,          "AnnotateHandle",           OCC::AnnotateHandle,           "annotateHandle",            {  true, false, false, false, false, false, false, false, false, false, false}, Attribute::ReadNone, },
 };
 // OPCODE-OLOADS:END
 
@@ -810,6 +814,11 @@ void OP::GetMinShaderModelAndMask(OpCode C, bool bWithTranslation,
     mask = SFLAG(Mesh);
     return;
   }
+  // Instructions: CreateHandleFromHeap=216, AnnotateHandle=217
+  if ((216 <= op && op <= 217)) {
+    major = 6;  minor = 6;
+    return;
+  }
   // OPCODE-SMMASK:END
 }
 
@@ -866,7 +875,11 @@ OP::OP(LLVMContext &Ctx, Module *pModule)
   memset(m_OpCodeClassCache, 0, sizeof(m_OpCodeClassCache));
   static_assert(_countof(OP::m_OpCodeProps) == (size_t)OP::OpCode::NumOpCodes, "forgot to update OP::m_OpCodeProps");
 
-  m_pHandleType = GetOrCreateStructType(m_Ctx, Type::getInt8PtrTy(m_Ctx), "dx.types.Handle", pModule);
+  m_pHandleType = GetOrCreateStructType(m_Ctx, Type::getInt8PtrTy(m_Ctx),
+                                        "dx.types.Handle", pModule);
+  m_pResourcePropertiesType = GetOrCreateStructType(
+      m_Ctx, {Type::getInt32Ty(m_Ctx), Type::getInt32Ty(m_Ctx)},
+      "dx.types.ResourceProperties", pModule);
 
   Type *DimsType[4] = { Type::getInt32Ty(m_Ctx), Type::getInt32Ty(m_Ctx), Type::getInt32Ty(m_Ctx), Type::getInt32Ty(m_Ctx) };
   m_pDimensionsType = GetOrCreateStructType(m_Ctx, DimsType, "dx.types.Dimensions", pModule);
@@ -940,6 +953,7 @@ Function *OP::GetOpFunc(OpCode opCode, Type *pOverloadType) {
   Type *pI4S = GetInt4Type(); // 4 i32s in a struct.
   Type *udt = pOverloadType;
   Type *obj = pOverloadType;
+  Type *resProperty = GetResourcePropertiesType();
 
   std::string funcName = (Twine(OP::m_NamePrefix) + Twine(GetOpCodeClassName(opCode))).str();
   // Add ret type to the name.
@@ -1302,6 +1316,10 @@ Function *OP::GetOpFunc(OpCode opCode, Type *pOverloadType) {
     // Inline Ray Query
   case OpCode::RayQuery_CandidateInstanceContributionToHitGroupIndex:A(pI32);     A(pI32); A(pI32); break;
   case OpCode::RayQuery_CommittedInstanceContributionToHitGroupIndex:A(pI32);     A(pI32); A(pI32); break;
+
+    // Get handle from heap
+  case OpCode::CreateHandleFromHeap:   A(pRes);     A(pI32); A(pI32); break;
+  case OpCode::AnnotateHandle:         A(pRes);     A(pI32); A(pRes); A(pI8);  A(pI8);  A(resProperty);break;
   // OPCODE-OLOAD-FUNCS:END
   default: DXASSERT(false, "otherwise unhandled case"); break;
   }
@@ -1469,6 +1487,8 @@ llvm::Type *OP::GetOverloadType(OpCode opCode, llvm::Function *F) {
   case OpCode::RayQuery_Abort:
   case OpCode::RayQuery_CommitNonOpaqueTriangleHit:
   case OpCode::RayQuery_CommitProceduralPrimitiveHit:
+  case OpCode::CreateHandleFromHeap:
+  case OpCode::AnnotateHandle:
     return Type::getVoidTy(m_Ctx);
   case OpCode::CheckAccessFullyMapped:
   case OpCode::AtomicBinOp:
@@ -1567,6 +1587,10 @@ Type *OP::GetHandleType() const {
   return m_pHandleType;
 }
 
+Type *OP::GetResourcePropertiesType() const {
+  return m_pResourcePropertiesType;
+}
+
 Type *OP::GetDimensionsType() const
 {
   return m_pDimensionsType;

+ 10 - 1
lib/DXIL/DxilResource.cpp

@@ -121,7 +121,8 @@ bool DxilResource::IsAnyTexture(Kind ResourceKind) {
 }
 
 bool DxilResource::IsStructuredBuffer() const {
-  return GetKind() == Kind::StructuredBuffer;
+  return GetKind() == Kind::StructuredBuffer ||
+         GetKind() == Kind::StructuredBufferWithCounter;
 }
 
 bool DxilResource::IsTypedBuffer() const {
@@ -161,6 +162,8 @@ unsigned DxilResource::GetNumCoords(Kind ResourceKind) {
       0, // RaytracingAccelerationStructure,
       2, // FeedbackTexture2D,
       3, // FeedbackTexture2DArray,
+      2, // StructureBufferWithCounter,
+      0, // SamplerComparation,
   };
   static_assert(_countof(CoordSizeTab) == (unsigned)Kind::NumEntries, "check helper array size");
   DXASSERT(ResourceKind > Kind::Invalid && ResourceKind < Kind::NumEntries, "otherwise the caller passed wrong resource type");
@@ -188,6 +191,8 @@ unsigned DxilResource::GetNumDimensions(Kind ResourceKind) {
       0, // RaytracingAccelerationStructure,
       2, // FeedbackTexture2D,
       2, // FeedbackTexture2DArray,
+      2, // StructureBufferWithCounter,
+      0, // SamplerComparation,
   };
   static_assert(_countof(NumDimTab) == (unsigned)Kind::NumEntries, "check helper array size");
   DXASSERT(ResourceKind > Kind::Invalid && ResourceKind < Kind::NumEntries, "otherwise the caller passed wrong resource type");
@@ -215,6 +220,8 @@ unsigned DxilResource::GetNumDimensionsForCalcLOD(Kind ResourceKind) {
       0, // RaytracingAccelerationStructure,
       2, // FeedbackTexture2D,
       2, // FeedbackTexture2DArray,
+      2, // StructureBufferWithCounter,
+      0, // SamplerComparation,
   };
   static_assert(_countof(NumDimTab) == (unsigned)Kind::NumEntries, "check helper array size");
   DXASSERT(ResourceKind > Kind::Invalid && ResourceKind < Kind::NumEntries, "otherwise the caller passed wrong resource type");
@@ -242,6 +249,8 @@ unsigned DxilResource::GetNumOffsets(Kind ResourceKind) {
       0, // RaytracingAccelerationStructure,
       2, // FeedbackTexture2D,
       2, // FeedbackTexture2DArray,
+      0, // StructureBufferWithCounter,
+      0, // SamplerComparation,
   };
   static_assert(_countof(OffsetSizeTab) == (unsigned)Kind::NumEntries, "check helper array size");
   DXASSERT(ResourceKind > Kind::Invalid && ResourceKind < Kind::NumEntries, "otherwise the caller passed wrong resource type");

+ 1 - 1
lib/DXIL/DxilResourceBase.cpp

@@ -90,7 +90,7 @@ static const char *s_ResourceDimNames[] = {
         "invalid", "1d",        "2d",      "2dMS",      "3d",
         "cube",    "1darray",   "2darray", "2darrayMS", "cubearray",
         "buf",     "rawbuf",    "structbuf", "cbuffer", "sampler",
-        "tbuffer", "ras", "fbtex2d", "fbtex2darray"
+        "tbuffer", "ras", "fbtex2d", "fbtex2darray", "structbufwithcounter", "samplercomparison",
 };
 static_assert(_countof(s_ResourceDimNames) == (unsigned)DxilResourceBase::Kind::NumEntries,
   "Resource dim names array must be updated when new resource kind enums are added.");

+ 199 - 0
lib/DXIL/DxilResourceProperties.cpp

@@ -0,0 +1,199 @@
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// DxilResourceProperites.cpp                                                //
+// Copyright (C) Microsoft Corporation. All rights reserved.                 //
+// This file is distributed under the University of Illinois Open Source     //
+// License. See LICENSE.TXT for details.                                     //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+#include "dxc/DXIL/DxilResourceProperties.h"
+#include "llvm/IR/Constant.h"
+#include "dxc/DXIL/DxilShaderModel.h"
+#include "llvm/IR/DerivedTypes.h"
+#include "llvm/IR/Constants.h"
+#include "dxc/DXIL/DxilResourceBase.h"
+#include "dxc/DXIL/DxilResource.h"
+#include "dxc/DXIL/DxilCBuffer.h"
+#include "dxc/DXIL/DxilSampler.h"
+#include "dxc/DXIL/DxilOperations.h"
+#include "dxc/DXIL/DxilInstructions.h"
+#include "dxc/DXIL/DxilUtil.h"
+
+using namespace llvm;
+
+namespace hlsl {
+
+bool DxilResourceProperties::operator==(const DxilResourceProperties &RP) {
+  return Class == RP.Class && Kind == RP.Kind && RawDword0 == RP.RawDword0 &&
+         RawDword1 == RP.RawDword1;
+}
+
+bool DxilResourceProperties::operator!=(const DxilResourceProperties &RP) {
+  return !(*this == RP) ;
+}
+
+namespace resource_helper {
+// Resource Class and Resource Kind is used as seperate parameter, other fileds
+// are saved in constant.
+// The constant is as struct with int32 fields.
+// ShaderModel 6.6 has 2 fileds.
+Constant *getAsConstant(const DxilResourceProperties &RP, Type *Ty,
+                        const ShaderModel &) {
+  StructType *ST = cast<StructType>(Ty);
+  switch (ST->getNumElements()) {
+  case 2: {
+    Constant *RawDwords[] = {
+        ConstantInt::get(ST->getElementType(0), RP.RawDword0),
+        ConstantInt::get(ST->getElementType(1), RP.RawDword1)};
+    return ConstantStruct::get(ST, RawDwords);
+  } break;
+  default:
+    return nullptr;
+    break;
+  }
+  return nullptr;
+}
+
+DxilResourceProperties loadFromConstant(const Constant &C,
+                                        DXIL::ResourceClass RC,
+                                        DXIL::ResourceKind RK, Type *Ty,
+                                        const ShaderModel &) {
+  DxilResourceProperties RP;
+  RP.Class = RC;
+  RP.Kind = RK;
+  // Ty Should match C.getType().
+  StructType *ST = cast<StructType>(Ty);
+  switch (ST->getNumElements()) {
+  case 2: {
+    const ConstantStruct *CS = cast<ConstantStruct>(&C);
+    const Constant *RawDword0 = CS->getOperand(0);
+    const Constant *RawDword1 = CS->getOperand(1);
+    RP.RawDword0 = cast<ConstantInt>(RawDword0)->getLimitedValue();
+    RP.RawDword1 = cast<ConstantInt>(RawDword1)->getLimitedValue();
+  } break;
+  default:
+    RP.Class = DXIL::ResourceClass::Invalid;
+    break;
+  }
+  return RP;
+}
+
+DxilResourceProperties
+loadFromAnnotateHandle(DxilInst_AnnotateHandle &annotateHandle, llvm::Type *Ty,
+                       const ShaderModel &SM) {
+
+  ConstantStruct *ResProp =
+      cast<ConstantStruct>(annotateHandle.get_props());
+  return loadFromConstant(
+      *ResProp, (DXIL::ResourceClass)annotateHandle.get_resourceClass_val(),
+      (DXIL::ResourceKind)annotateHandle.get_resourceKind_val(), Ty, SM);
+}
+
+DxilResourceProperties loadFromResourceBase(DxilResourceBase *Res) {
+
+  DxilResourceProperties RP;
+  RP.Class = DXIL::ResourceClass::Invalid;
+  if (!Res) {
+    return RP;
+  }
+
+  RP.RawDword0 = 0;
+  RP.RawDword1 = 0;
+
+  auto SetResProperties = [&RP](DxilResource &Res) {
+    switch (Res.GetKind()) {
+    default:
+      break;
+    case DXIL::ResourceKind::FeedbackTexture2D:
+    case DXIL::ResourceKind::FeedbackTexture2DArray:
+      RP.SamplerFeedbackType = Res.GetSamplerFeedbackType();
+      break;
+    case DXIL::ResourceKind::RTAccelerationStructure:
+
+      break;
+    case DXIL::ResourceKind::StructuredBuffer:
+    case DXIL::ResourceKind::StructuredBufferWithCounter:
+      RP.ElementStride = Res.GetElementStride();
+      break;
+    case DXIL::ResourceKind::Texture2DMS:
+    case DXIL::ResourceKind::Texture2DMSArray:
+      switch (Res.GetSampleCount()) {
+      default:
+        RP.Typed.SampleCountPow2 =
+            DxilResourceProperties::kSampleCountUndefined;
+        break;
+      case 1:
+        RP.Typed.SampleCountPow2 = 0;
+        break;
+      case 2:
+        RP.Typed.SampleCountPow2 = 1;
+        break;
+      case 4:
+        RP.Typed.SampleCountPow2 = 2;
+        break;
+      case 8:
+        RP.Typed.SampleCountPow2 = 3;
+        break;
+      case 16:
+        RP.Typed.SampleCountPow2 = 4;
+        break;
+      case 32:
+        RP.Typed.SampleCountPow2 = 5;
+        break;
+      }
+      break;
+    case DXIL::ResourceKind::TypedBuffer:
+    case DXIL::ResourceKind::Texture1D:
+    case DXIL::ResourceKind::Texture2D:
+    case DXIL::ResourceKind::TextureCube:
+    case DXIL::ResourceKind::Texture1DArray:
+    case DXIL::ResourceKind::Texture2DArray:
+    case DXIL::ResourceKind::TextureCubeArray:
+    case DXIL::ResourceKind::Texture3D:
+      Type *Ty = Res.GetRetType();
+      RP.Typed.SingleComponent = dxilutil::IsResourceSingleComponent(Ty);
+      RP.Typed.CompType = Res.GetCompType().GetKind();
+      break;
+    }
+  };
+
+  switch (Res->GetClass()) { case DXIL::ResourceClass::Invalid: return RP;
+  case DXIL::ResourceClass::SRV: {
+    DxilResource *SRV = (DxilResource*)(Res);
+    RP.Kind = Res->GetKind();
+    RP.Class = Res->GetClass();
+    SetResProperties(*SRV);
+  } break;
+  case DXIL::ResourceClass::UAV: {
+    DxilResource *UAV = (DxilResource *)(Res);
+    RP.Kind = Res->GetKind();
+    RP.Class = Res->GetClass();
+    RP.UAV.bGloballyCoherent = UAV->IsGloballyCoherent();
+    if (UAV->HasCounter()) {
+      RP.Kind = DXIL::ResourceKind::StructuredBufferWithCounter;
+    }
+    RP.UAV.bROV = UAV->IsROV();
+    SetResProperties(*UAV);
+  } break;
+  case DXIL::ResourceClass::Sampler: {
+    RP.Class = DXIL::ResourceClass::Sampler;
+    RP.Kind = Res->GetKind();
+    DxilSampler *Sampler = (DxilSampler*)Res;
+    if (Sampler->GetSamplerKind() == DXIL::SamplerKind::Comparison)
+      RP.Kind = DXIL::ResourceKind::SamplerComparison;
+    else if (Sampler->GetSamplerKind() == DXIL::SamplerKind::Invalid)
+      RP.Kind = DXIL::ResourceKind::Invalid;
+  } break;
+  case DXIL::ResourceClass::CBuffer: {
+    RP.Class = DXIL::ResourceClass::CBuffer;
+    RP.Kind = Res->GetKind();
+    DxilCBuffer *CB = (DxilCBuffer *)Res;
+    RP.SizeInBytes = CB->GetSize();
+  } break;
+  }
+  return RP;
+}
+
+} // namespace resource_helper
+} // namespace hlsl

+ 24 - 24
lib/DXIL/DxilShaderFlags.cpp

@@ -17,6 +17,9 @@
 #include "llvm/IR/Constants.h"
 #include "llvm/Support/Casting.h"
 #include "dxc/DXIL/DxilEntryProps.h"
+#include "dxc/DXIL/DxilInstructions.h"
+#include "dxc/DXIL/DxilResourceProperties.h"
+#include "dxc/DXIL/DxilUtil.h"
 
 using namespace hlsl;
 using namespace llvm;
@@ -189,28 +192,6 @@ static ConstantInt *GetArbitraryConstantRangeID(CallInst *handleCall) {
   return ConstantRangeID;
 }
 
-static bool IsResourceSingleComponent(llvm::Type *Ty) {
-  if (llvm::ArrayType *arrType = llvm::dyn_cast<llvm::ArrayType>(Ty)) {
-    if (arrType->getArrayNumElements() > 1) {
-      return false;
-    }
-    return IsResourceSingleComponent(arrType->getArrayElementType());
-  } else if (llvm::StructType *structType =
-                 llvm::dyn_cast<llvm::StructType>(Ty)) {
-    if (structType->getStructNumElements() > 1) {
-      return false;
-    }
-    return IsResourceSingleComponent(structType->getStructElementType(0));
-  } else if (llvm::VectorType *vectorType =
-                 llvm::dyn_cast<llvm::VectorType>(Ty)) {
-    if (vectorType->getNumElements() > 1) {
-      return false;
-    }
-    return IsResourceSingleComponent(vectorType->getVectorElementType());
-  }
-  return true;
-}
-
 // Given a handle type, find an arbitrary call instructions to create handle
 static CallInst *FindCallToCreateHandle(Value *handleType) {
   Value *curVal = handleType;
@@ -351,7 +332,7 @@ ShaderFlags ShaderFlags::CollectShaderFlags(const Function *F,
                       DxilResource resource = M->GetUAV(rangeID->getLimitedValue());
                       if ((resource.IsTypedBuffer() ||
                         resource.IsAnyTexture()) &&
-                        !IsResourceSingleComponent(resource.GetRetType())) {
+                        !dxilutil::IsResourceSingleComponent(resource.GetRetType())) {
                         hasMulticomponentUAVLoads = true;
                       }
                     }
@@ -371,12 +352,31 @@ ShaderFlags ShaderFlags::CollectShaderFlags(const Function *F,
                 for (auto &&res : M->GetUAVs()) {
                   if (res->GetGlobalSymbol() == resType) {
                     if ((res->IsTypedBuffer() || res->IsAnyTexture()) &&
-                        !IsResourceSingleComponent(res->GetRetType())) {
+                        !dxilutil::IsResourceSingleComponent(res->GetRetType())) {
                       hasMulticomponentUAVLoads = true;
                     }
                   }
                 }
               }
+            } else if (handleOp == DXIL::OpCode::AnnotateHandle) {
+              DxilInst_AnnotateHandle annotateHandle(handleCall);
+              Type *ResPropTy = M->GetOP()->GetResourcePropertiesType();
+
+              DxilResourceProperties RP =
+                  resource_helper::loadFromAnnotateHandle(
+                      annotateHandle, ResPropTy, *M->GetShaderModel());
+              if (RP.Class == DXIL::ResourceClass::UAV) {
+                // Validator 1.0 assumes that all uav load is multi component
+                // load.
+                if (hasMulticomponentUAVLoadsBackCompat) {
+                  hasMulticomponentUAVLoads = true;
+                  continue;
+                } else {
+                  if (DXIL::IsTyped(RP.Kind) &&
+                      !RP.Typed.SingleComponent)
+                    hasMulticomponentUAVLoads = true;
+                }
+              }
             }
           }
        } break;

+ 35 - 0
lib/DXIL/DxilUtil.cpp

@@ -495,6 +495,28 @@ static bool ConsumePrefix(StringRef &Str, StringRef Prefix) {
   return true;
 }
 
+bool IsResourceSingleComponent(Type *Ty) {
+  if (llvm::ArrayType *arrType = llvm::dyn_cast<llvm::ArrayType>(Ty)) {
+    if (arrType->getArrayNumElements() > 1) {
+      return false;
+    }
+    return IsResourceSingleComponent(arrType->getArrayElementType());
+  } else if (llvm::StructType *structType =
+                 llvm::dyn_cast<llvm::StructType>(Ty)) {
+    if (structType->getStructNumElements() > 1) {
+      return false;
+    }
+    return IsResourceSingleComponent(structType->getStructElementType(0));
+  } else if (llvm::VectorType *vectorType =
+                 llvm::dyn_cast<llvm::VectorType>(Ty)) {
+    if (vectorType->getNumElements() > 1) {
+      return false;
+    }
+    return IsResourceSingleComponent(vectorType->getVectorElementType());
+  }
+  return true;
+}
+
 bool IsHLSLResourceType(llvm::Type *Ty) {
   if (llvm::StructType *ST = dyn_cast<llvm::StructType>(Ty)) {
     if (!ST->hasName())
@@ -602,6 +624,19 @@ bool IsHLSLRayQueryType(llvm::Type *Ty) {
   return false;
 }
 
+bool IsHLSLResourceDescType(llvm::Type *Ty) {
+  if (llvm::StructType *ST = dyn_cast<llvm::StructType>(Ty)) {
+    if (!ST->hasName())
+      return false;
+    StringRef name = ST->getName();
+
+    // TODO: don't check names.
+    if (name == ("struct..Resource"))
+      return true;
+  }
+  return false;
+}
+
 bool IsIntegerOrFloatingPointType(llvm::Type *Ty) {
   return Ty->isIntegerTy() || Ty->isFloatingPointTy();
 }

+ 7 - 1
lib/HLSL/DxilCondenseResources.cpp

@@ -1927,7 +1927,7 @@ void UpdateStructTypeForLegacyLayoutOnDM(DxilModule &DM) {
   }
 
   for (auto &UAV : DM.GetUAVs()) {
-    if (UAV->GetKind() == DxilResourceBase::Kind::StructuredBuffer)
+    if (DXIL::IsStructuredBuffer(UAV->GetKind()))
       UpdateStructTypeForLegacyLayout(*UAV.get(), TypeSys, M);
   }
 
@@ -2284,6 +2284,9 @@ void PatchTBufferLoad(CallInst *handle, DxilModule &DM) {
       // TODO: Handle this, or prevent this for tbuffer
       DXASSERT(false, "otherwise CBufferLoad used for tbuffer rather than "
                       "CBufferLoadLegacy");
+    } else if (opcode == DXIL::OpCode::AnnotateHandle) {
+      DxilInst_AnnotateHandle annotateHandle(I);
+      PatchTBufferLoad(cast<CallInst>(annotateHandle.get_res()), DM);
     } else {
       DXASSERT(false, "otherwise unexpected user of CreateHandle value");
     }
@@ -2415,6 +2418,9 @@ static void CollectCBufferMemberUsage(Value *V,
         hlsl::OP::OpCode op = hlslOP->GetDxilOpFuncCallInst(CI);
         if (op == DXIL::OpCode::CreateHandleForLib) {
           CollectCBufferMemberUsage(U, legacyFieldMap, newFieldMap, hlslOP, bMinPrecision);
+        } else if (op == DXIL::OpCode::AnnotateHandle) {
+          CollectCBufferMemberUsage(U, legacyFieldMap, newFieldMap, hlslOP,
+                                    bMinPrecision);
         } else if (op == DXIL::OpCode::CBufferLoadLegacy) {
           DxilInst_CBufferLoadLegacy cbload(CI);
           Value *resIndex = cbload.get_regIndex();

+ 7 - 2
lib/HLSL/DxilContainerReflection.cpp

@@ -1384,7 +1384,8 @@ static D3D_SHADER_INPUT_TYPE ResourceToShaderInputType(DxilResourceBase *RB) {
     return D3D_SIT_SAMPLER;
   case DxilResource::Kind::RawBuffer:
     return isUAV ? D3D_SIT_UAV_RWBYTEADDRESS : D3D_SIT_BYTEADDRESS;
-  case DxilResource::Kind::StructuredBuffer: {
+  case DxilResource::Kind::StructuredBuffer:
+  case DxilResource::Kind::StructuredBufferWithCounter: {
     if (!isUAV) return D3D_SIT_STRUCTURED;
     // TODO: D3D_SIT_UAV_CONSUME_STRUCTURED, D3D_SIT_UAV_APPEND_STRUCTURED?
     if (R->HasCounter()) return D3D_SIT_UAV_RWSTRUCTURED_WITH_COUNTER;
@@ -1615,6 +1616,10 @@ static void CollectCBufUsage(Value *cbHandle,
       Value *byteOffset = cbload.get_byteOffset();
       unsigned offset = GetCBOffset(byteOffset);
       cbufUsage.emplace_back(offset);
+    } else if (opcode == DXIL::OpCode::AnnotateHandle) {
+      DxilInst_AnnotateHandle annotateHandle(CI);
+      Value *annotatedHandle = annotateHandle.get_res();
+      CollectCBufUsage(annotatedHandle, cbufUsage, bMinPrecision);
     } else {
       //
       DXASSERT(0, "invalid opcode");
@@ -1711,7 +1716,7 @@ void DxilModuleReflection::CreateReflectionObjects() {
 
   // TODO: add tbuffers into m_CBs
   for (auto && uav : m_pDxilModule->GetUAVs()) {
-    if (uav->GetKind() != DxilResource::Kind::StructuredBuffer) {
+    if (!DXIL::IsStructuredBuffer(uav->GetKind())) {
       continue;
     }
     std::unique_ptr<CShaderReflectionConstantBuffer> rcb(new CShaderReflectionConstantBuffer());

+ 280 - 3
lib/HLSL/DxilGenerationPass.cpp

@@ -13,6 +13,7 @@
 #include "dxc/DXIL/DxilEntryProps.h"
 #include "dxc/DXIL/DxilModule.h"
 #include "dxc/DXIL/DxilOperations.h"
+#include "dxc/DXIL/DxilInstructions.h"
 #include "dxc/DXIL/DxilUtil.h"
 #include "dxc/HLSL/DxilGenerationPass.h"
 #include "dxc/HLSL/HLSLExtensionsCodegenHelper.h"
@@ -250,7 +251,9 @@ public:
 
     GenerateDxilCBufferHandles();
     MarkUpdateCounter(UpdateCounterSet);
-    LowerHLCreateHandle();
+
+    std::unordered_map<CallInst *, Type*> HandleToResTypeMap;
+    LowerHLCreateHandle(HandleToResTypeMap);
 
     // LowerHLCreateHandle() should have translated HLCreateHandle to CreateHandleForLib.
     // Clean up HLCreateHandle functions.
@@ -287,6 +290,10 @@ public:
     HLModule::ClearHLMetadata(M);
     M.ResetHLModule();
 
+    if (SM->IsSM62Plus() && DxilMod.GetUseMinPrecision()) {
+      TranslateMinPrecisionRawBuffer(DxilMod, HandleToResTypeMap);
+    }
+
     // We now have a DXIL representation - record this.
     SetPauseResumePasses(M, "hlsl-dxilemit", "hlsl-dxilload");
 
@@ -304,10 +311,20 @@ private:
   // change built-in funtion into DXIL operations
   void GenerateDxilOperations(Module &M,
                               std::unordered_set<LoadInst *> &UpdateCounterSet);
-  void LowerHLCreateHandle();
+  void LowerHLCreateHandle(
+      std::unordered_map<CallInst *, Type *> &HandleToResTypeMap);
 
   // Translate precise attribute into HL function call.
   void TranslatePreciseAttribute();
+  // Translate RawBufferLoad/RawBufferStore
+  // For DXIL >= 1.2, if min precision is enabled, currently generation pass is
+  // producing i16/f16 return type for min precisions. For rawBuffer, we will
+  // change this so that min precisions are returning its actual scalar type
+  // (i32/f32) and will be truncated to their corresponding types after loading
+  // / before storing.
+  void TranslateMinPrecisionRawBuffer(
+      DxilModule &DM,
+      std::unordered_map<CallInst *, Type *> &HandleToResTypeMap);
 
   // Input module is not optimized.
   bool NotOptimized;
@@ -343,11 +360,87 @@ void TranslateHLCreateHandle(Function *F, hlsl::OP &hlslOP) {
     CI->eraseFromParent();
   }
 }
+
+void TranslateHLAnnotateHandle(
+    Function *F, hlsl::OP &hlslOP,
+    std::unordered_map<CallInst *, Type *> &HandleToResTypeMap) {
+  Value *opArg = hlslOP.GetU32Const((unsigned)DXIL::OpCode::AnnotateHandle);
+
+  for (auto U = F->user_begin(); U != F->user_end();) {
+    Value *user = *(U++);
+    if (!isa<Instruction>(user))
+      continue;
+    // must be call inst
+    CallInst *CI = cast<CallInst>(user);
+    Value *handle =
+        CI->getArgOperand(HLOperandIndex::kAnnotateHandleHandleOpIdx);
+    Value *RC =
+        CI->getArgOperand(HLOperandIndex::kAnnotateHandleResourceClassOpIdx);
+    Value *RK =
+        CI->getArgOperand(HLOperandIndex::kAnnotateHandleResourceKindOpIdx);
+    Value *RP = CI->getArgOperand(
+        HLOperandIndex::kAnnotateHandleResourcePropertiesOpIdx);
+    Type *ResTy =
+        CI->getArgOperand(HLOperandIndex::kAnnotateHandleResourceTypeOpIdx)
+            ->getType();
+    IRBuilder<> Builder(CI);
+
+    Function *annotateHandle =
+        hlslOP.GetOpFunc(DXIL::OpCode::AnnotateHandle, Builder.getVoidTy());
+    CallInst *newHandle =
+        Builder.CreateCall(annotateHandle, {opArg, handle, RC, RK, RP});
+    HandleToResTypeMap[newHandle] = ResTy;
+    CI->replaceAllUsesWith(newHandle);
+    CI->eraseFromParent();
+  }
+}
+
+void TranslateHLCastHandleToRes(Function *F, hlsl::OP &hlslOP) {
+  for (auto U = F->user_begin(); U != F->user_end();) {
+    Value *User = *(U++);
+    if (!isa<Instruction>(User))
+      continue;
+    // must be call inst
+    CallInst *CI = cast<CallInst>(User);
+    IRBuilder<> Builder(CI);
+    HLCastOpcode opcode = static_cast<HLCastOpcode>(hlsl::GetHLOpcode(CI));
+    switch (opcode) {
+    case HLCastOpcode::HandleToResCast: {
+      Value *Handle = CI->getArgOperand(HLOperandIndex::kUnaryOpSrc0Idx);
+      for (auto HandleU = CI->user_begin(); HandleU != CI->user_end();) {
+        Value *HandleUser = *(HandleU++);
+        CallInst *HandleCI = dyn_cast<CallInst>(HandleUser);
+        if (!HandleCI)
+          continue;
+        hlsl::HLOpcodeGroup handleGroup =
+            hlsl::GetHLOpcodeGroup(HandleCI->getCalledFunction());
+        if (handleGroup == HLOpcodeGroup::HLCreateHandle) {
+          HandleCI->replaceAllUsesWith(Handle);
+          HandleCI->eraseFromParent();
+        }
+      }
+      if (CI->user_empty()) {
+        CI->eraseFromParent();
+      }
+    } break;
+    }
+  }
+}
 } // namespace
 
-void DxilGenerationPass::LowerHLCreateHandle() {
+void DxilGenerationPass::LowerHLCreateHandle(
+    std::unordered_map<CallInst *, Type *> &HandleToResTypeMap) {
   Module *M = m_pHLModule->GetModule();
   hlsl::OP &hlslOP = *m_pHLModule->GetOP();
+  // Lower cast handle to res used by hl.createhandle.
+  for (iplist<Function>::iterator F : M->getFunctionList()) {
+    if (F->user_empty())
+      continue;
+    hlsl::HLOpcodeGroup group = hlsl::GetHLOpcodeGroup(F);
+    if (group == HLOpcodeGroup::HLCast) {
+      TranslateHLCastHandleToRes(F, hlslOP);
+    }
+  }
   // generate dxil operation
   for (iplist<Function>::iterator F : M->getFunctionList()) {
     if (F->user_empty())
@@ -358,6 +451,11 @@ void DxilGenerationPass::LowerHLCreateHandle() {
         // Will lower in later pass.
         TranslateHLCreateHandle(F, hlslOP);
       }
+    } else {
+      hlsl::HLOpcodeGroup group = hlsl::GetHLOpcodeGroup(F);
+      if (group != HLOpcodeGroup::HLAnnotateHandle)
+        continue;
+      TranslateHLAnnotateHandle(F, hlslOP, HandleToResTypeMap);
     }
   }
 }
@@ -581,6 +679,185 @@ void DxilGenerationPass::TranslatePreciseAttribute() {
   }
 }
 
+namespace {
+void ReplaceMinPrecisionRawBufferLoadByType(Function *F, Type *FromTy,
+                                            Type *ToTy, OP *Op,
+                                            const DataLayout &DL) {
+  Function *newFunction = Op->GetOpFunc(DXIL::OpCode::RawBufferLoad, ToTy);
+  for (auto FUser = F->user_begin(), FEnd = F->user_end(); FUser != FEnd;) {
+    User *UserCI = *(FUser++);
+    if (CallInst *CI = dyn_cast<CallInst>(UserCI)) {
+      IRBuilder<> CIBuilder(CI);
+      SmallVector<Value *, 5> newFuncArgs;
+      // opcode, handle, index, elementOffset, mask
+      // Compiler is generating correct element offset even for min precision
+      // types So no need to recalculate here
+      for (unsigned i = 0; i < 5; ++i) {
+        newFuncArgs.emplace_back(CI->getArgOperand(i));
+      }
+      // new alignment for new type
+      newFuncArgs.emplace_back(Op->GetI32Const(DL.getTypeAllocSize(ToTy)));
+      CallInst *newCI = CIBuilder.CreateCall(newFunction, newFuncArgs);
+      for (auto CIUser = CI->user_begin(), CIEnd = CI->user_end();
+           CIUser != CIEnd;) {
+        User *UserEV = *(CIUser++);
+        if (ExtractValueInst *EV = dyn_cast<ExtractValueInst>(UserEV)) {
+          IRBuilder<> EVBuilder(EV);
+          ArrayRef<unsigned> Indices = EV->getIndices();
+          DXASSERT(Indices.size() == 1,
+                   "Otherwise we have wrong extract value.");
+          Value *newEV = EVBuilder.CreateExtractValue(newCI, Indices);
+          Value *newTruncV = nullptr;
+          if (4 == Indices[0]) { // Don't truncate status
+            newTruncV = newEV;
+          } else if (FromTy->isHalfTy()) {
+            newTruncV = EVBuilder.CreateFPTrunc(newEV, FromTy);
+          } else if (FromTy->isIntegerTy()) {
+            newTruncV = EVBuilder.CreateTrunc(newEV, FromTy);
+          } else {
+            DXASSERT(false, "unexpected type conversion");
+          }
+          EV->replaceAllUsesWith(newTruncV);
+          EV->eraseFromParent();
+        }
+      }
+      CI->eraseFromParent();
+    }
+  }
+  F->eraseFromParent();
+}
+
+void ReplaceMinPrecisionRawBufferStoreByType(
+    Function *F, Type *FromTy, Type *ToTy, OP *Op,
+    std::unordered_map<CallInst *, Type *> &HandleToResTypeMap,
+    DxilTypeSystem &typeSys, const DataLayout &DL) {
+  Function *newFunction = Op->GetOpFunc(DXIL::OpCode::RawBufferStore, ToTy);
+  // for each function
+  // add argument 4-7 to its upconverted values
+  // replace function call
+  for (auto FuncUser = F->user_begin(), FuncEnd = F->user_end();
+       FuncUser != FuncEnd;) {
+    CallInst *CI = dyn_cast<CallInst>(*(FuncUser++));
+    DXASSERT(CI, "function user must be a call instruction.");
+    IRBuilder<> CIBuilder(CI);
+    SmallVector<Value *, 9> Args;
+    for (unsigned i = 0; i < 4; ++i) {
+      Args.emplace_back(CI->getArgOperand(i));
+    }
+    // values to store should be converted to its higher precision types
+    if (FromTy->isHalfTy()) {
+      for (unsigned i = 4; i < 8; ++i) {
+        Value *NewV = CIBuilder.CreateFPExt(CI->getArgOperand(i),
+                                            ToTy);
+        Args.emplace_back(NewV);
+      }
+    } else if (FromTy->isIntegerTy()) {
+      // This case only applies to typed buffer since Store operation of byte
+      // address buffer for min precision is handled by implicit conversion on
+      // intrinsic call. Since we are extending integer, we have to know if we
+      // should sign ext or zero ext. We can do this by iterating checking the
+      // size of the element at struct type and comp type at type annotation
+      CallInst *handleCI = dyn_cast<CallInst>(
+          CI->getArgOperand(DxilInst_RawBufferStore::arg_uav));
+      DXASSERT(handleCI,
+               "otherwise handle was not an argument to buffer store.");
+      auto resTyIt = HandleToResTypeMap.find(handleCI);
+      DXASSERT(resTyIt != HandleToResTypeMap.end(),
+               "otherwise fail to handle for buffer store lost its retTy");
+      StructType *STy = dyn_cast<StructType>(resTyIt->second);
+
+      STy = cast<StructType>(STy->getElementType(0));
+      DxilStructAnnotation *SAnnot =
+          typeSys.GetStructAnnotation(STy);
+      ConstantInt *offsetInt = dyn_cast<ConstantInt>(
+          CI->getArgOperand(DxilInst_RawBufferStore::arg_elementOffset));
+      unsigned offset = offsetInt->getSExtValue();
+      unsigned currentOffset = 0;
+      for (DxilStructTypeIterator iter = begin(STy, SAnnot),
+                                  ItEnd = end(STy, SAnnot);
+           iter != ItEnd; ++iter) {
+        std::pair<Type *, DxilFieldAnnotation *> pair = *iter;
+        currentOffset += DL.getTypeAllocSize(pair.first);
+        if (currentOffset > offset) {
+          if (pair.second->GetCompType().IsUIntTy()) {
+            for (unsigned i = 4; i < 8; ++i) {
+              Value *NewV = CIBuilder.CreateZExt(CI->getArgOperand(i), ToTy);
+              Args.emplace_back(NewV);
+            }
+            break;
+          } else if (pair.second->GetCompType().IsIntTy()) {
+            for (unsigned i = 4; i < 8; ++i) {
+              Value *NewV = CIBuilder.CreateSExt(CI->getArgOperand(i), ToTy);
+              Args.emplace_back(NewV);
+            }
+            break;
+          } else {
+            DXASSERT(false, "Invalid comp type");
+          }
+        }
+      }
+    }
+
+    // mask
+    Args.emplace_back(CI->getArgOperand(8));
+    // alignment
+    Args.emplace_back(CIBuilder.getInt32(DL.getTypeAllocSize(ToTy)));
+    CIBuilder.CreateCall(newFunction, Args);
+    CI->eraseFromParent();
+  }
+}
+
+} // namespace
+void DxilGenerationPass::TranslateMinPrecisionRawBuffer(
+    DxilModule &DM,
+    std::unordered_map<CallInst *, Type *> &HandleToResTypeMap) {
+  hlsl::OP *hlslOP = DM.GetOP();
+  LLVMContext &Ctx = DM.GetCtx();
+  Type *I32Ty = Type::getInt32Ty(Ctx);
+  Type *I16Ty = Type::getInt16Ty(Ctx);
+  Type *F32Ty = Type::getFloatTy(Ctx);
+  Type *F16Ty = Type::getHalfTy(Ctx);
+  const DataLayout &DL = DM.GetModule()->getDataLayout();
+  DxilTypeSystem &typeSys = DM.GetTypeSystem();
+  SmallVector<Function *, 2> rawBufLoads;
+  for (auto it : hlslOP->GetOpFuncList(DXIL::OpCode::RawBufferLoad)) {
+    Function *F = it.second;
+    if (!F)
+      continue;
+    rawBufLoads.emplace_back(F);
+  }
+
+  for (Function *F : rawBufLoads) {
+    StructType *RetTy = cast<StructType>(F->getReturnType());
+    Type *EltTy = RetTy->getElementType(0);
+    if (EltTy->isHalfTy()) {
+      ReplaceMinPrecisionRawBufferLoadByType(F, F16Ty, F32Ty, hlslOP, DL);
+    } else if (EltTy == I16Ty) {
+      ReplaceMinPrecisionRawBufferLoadByType(F, I16Ty, I32Ty, hlslOP, DL);
+    }
+  }
+
+  SmallVector<Function *, 2> rawBufStores;
+  for (auto it : hlslOP->GetOpFuncList(DXIL::OpCode::RawBufferStore)) {
+    Function *F = it.second;
+    if (!F)
+      continue;
+    rawBufStores.emplace_back(F);
+  }
+
+  for (Function *F : rawBufStores) {
+    Type *EltTy =
+        F->getFunctionType()->getParamType(DxilInst_RawBufferStore::arg_value0);
+    if (EltTy->isHalfTy()) {
+      ReplaceMinPrecisionRawBufferStoreByType(F, F16Ty, F32Ty, hlslOP,
+                                              HandleToResTypeMap, typeSys, DL);
+    } else if (EltTy == I16Ty) {
+      ReplaceMinPrecisionRawBufferStoreByType(F, I16Ty, I32Ty, hlslOP,
+                                              HandleToResTypeMap, typeSys, DL);
+    }
+  }
+}
+
 char DxilGenerationPass::ID = 0;
 
 ModulePass *llvm::createDxilGenerationPass(bool NotOptimized, hlsl::HLSLExtensionsCodegenHelper *extensionsHelper) {

+ 1 - 1
lib/HLSL/DxilPatchShaderRecordBindings.cpp

@@ -457,7 +457,7 @@ llvm::Value *DxilPatchShaderRecordBindings::GetAliasedDescriptorHeapHandle(Modul
     
     ViewKey key = {};
     key.ViewType = (unsigned int)resKind;
-    if (resKind == DXIL::ResourceKind::StructuredBuffer)
+    if (DXIL::IsStructuredBuffer(resKind))
     {
       key.StructuredStride = type->getPrimitiveSizeInBits();
     } else if (resKind != DXIL::ResourceKind::RawBuffer)

+ 18 - 0
lib/HLSL/DxilPreparePasses.cpp

@@ -359,6 +359,21 @@ public:
     }
   }
 
+  void patchDxil_1_6(Module &M, hlsl::OP *hlslOP) {
+    for (auto it : hlslOP->GetOpFuncList(DXIL::OpCode::AnnotateHandle)) {
+      Function *F = it.second;
+      if (!F)
+        continue;
+      for (auto uit = F->user_begin(); uit != F->user_end();) {
+        CallInst *CI = cast<CallInst>(*(uit++));
+        DxilInst_AnnotateHandle annoteHdl(CI);
+        Value *hdl = annoteHdl.get_res();
+        CI->replaceAllUsesWith(hdl);
+        CI->eraseFromParent();
+      }
+    }
+  }
+
   bool runOnModule(Module &M) override {
     if (M.HasDxilModule()) {
       DxilModule &DM = M.GetDxilModule();
@@ -384,6 +399,9 @@ public:
 
       // Remove store undef output.
       hlsl::OP *hlslOP = M.GetDxilModule().GetOP();
+      if (DxilMinor < 6) {
+        patchDxil_1_6(M, hlslOP);
+      }
       RemoveStoreUndefOutput(M, hlslOP);
 
       RemoveUnusedStaticGlobal(M);

+ 1 - 178
lib/HLSL/DxilTranslateRawBuffer.cpp

@@ -32,10 +32,7 @@ using namespace hlsl;
 // This pass is to make sure that we generate correct buffer load for DXIL
 // For DXIL < 1.2, rawBufferLoad will be translated to BufferLoad instruction
 // without mask.
-// For DXIL >= 1.2, if min precision is enabled, currently generation pass is
-// producing i16/f16 return type for min precisions. For rawBuffer, we will
-// change this so that min precisions are returning its actual scalar type (i32/f32)
-// and will be truncated to their corresponding types after loading / before storing.
+
 namespace {
 
 class DxilTranslateRawBuffer : public ModulePass {
@@ -90,17 +87,6 @@ public:
           }
         }
       }
-    } else if (M.GetDxilModule().GetUseMinPrecision()) {
-      for (auto F = M.functions().begin(), E = M.functions().end(); F != E;) {
-        Function *func = &*(F++);
-        if (func->hasName()) {
-          if (func->getName().startswith("dx.op.rawBufferLoad")) {
-            ReplaceMinPrecisionRawBufferLoad(func, M);
-          } else if (func->getName().startswith("dx.op.rawBufferStore")) {
-            ReplaceMinPrecisionRawBufferStore(func, M);
-          }
-        }
-      }
     }
     return true;
   }
@@ -111,12 +97,6 @@ private:
   void ReplaceRawBufferStore(Function *F, Module &M);
   void ReplaceRawBufferLoad64Bit(Function *F, Type *EltTy, Module &M);
   void ReplaceRawBufferStore64Bit(Function *F, Type *EltTy, Module &M);
-  // Replace RawBufferLoad/Store of min-precision types to have its actual storage size
-  void ReplaceMinPrecisionRawBufferLoad(Function *F, Module &M);
-  void ReplaceMinPrecisionRawBufferStore(Function *F, Module &M);
-  void ReplaceMinPrecisionRawBufferLoadByType(Function *F, Type *FromTy,
-                                              Type *ToTy, OP *Op,
-                                              const DataLayout &DL);
 };
 } // namespace
 
@@ -139,163 +119,6 @@ void DxilTranslateRawBuffer::ReplaceRawBufferStore64Bit(Function *F, Type *ETy,
   dxilutil::ReplaceRawBufferStore64Bit(F, ETy, M.GetDxilModule().GetOP());
 }
 
-void DxilTranslateRawBuffer::ReplaceMinPrecisionRawBufferLoad(Function *F,
-                                                              Module &M) {
-  OP *Op = M.GetDxilModule().GetOP();
-  Type *RetTy = F->getReturnType();
-  if (StructType *STy = dyn_cast<StructType>(RetTy)) {
-    Type *EltTy = STy->getElementType(0);
-    if (EltTy->isHalfTy()) {
-      ReplaceMinPrecisionRawBufferLoadByType(F, Type::getHalfTy(M.getContext()),
-                                             Type::getFloatTy(M.getContext()),
-                                             Op, M.getDataLayout());
-    } else if (EltTy == Type::getInt16Ty(M.getContext())) {
-      ReplaceMinPrecisionRawBufferLoadByType(
-          F, Type::getInt16Ty(M.getContext()), Type::getInt32Ty(M.getContext()),
-          Op, M.getDataLayout());
-    }
-  } else {
-    DXASSERT(false, "RawBufferLoad should return struct type.");
-  }
-}
-
-void DxilTranslateRawBuffer::ReplaceMinPrecisionRawBufferStore(Function *F,
-                                                              Module &M) {
-  DXASSERT(F->getReturnType()->isVoidTy(), "rawBufferStore should return a void type.");
-  Type *ETy = F->getFunctionType()->getParamType(4); // value
-  Type *NewETy;
-  if (ETy->isHalfTy()) {
-    NewETy = Type::getFloatTy(M.getContext());
-  }
-  else if (ETy == Type::getInt16Ty(M.getContext())) {
-    NewETy = Type::getInt32Ty(M.getContext());
-  }
-  else {
-    return; // not a min precision type
-  }
-  Function *newFunction = M.GetDxilModule().GetOP()->GetOpFunc(
-      DXIL::OpCode::RawBufferStore, NewETy);
-  // for each function
-  // add argument 4-7 to its upconverted values
-  // replace function call
-  for (auto FuncUser = F->user_begin(), FuncEnd = F->user_end(); FuncUser != FuncEnd;) {
-    CallInst *CI = dyn_cast<CallInst>(*(FuncUser++));
-    DXASSERT(CI, "function user must be a call instruction.");
-    IRBuilder<> CIBuilder(CI);
-    SmallVector<Value *, 9> Args;
-    for (unsigned i = 0; i < 4; ++i) {
-      Args.emplace_back(CI->getArgOperand(i));
-    }
-    // values to store should be converted to its higher precision types
-    if (ETy->isHalfTy()) {
-      for (unsigned i = 4; i < 8; ++i) {
-        Value *NewV = CIBuilder.CreateFPExt(CI->getArgOperand(i),
-                                            Type::getFloatTy(M.getContext()));
-        Args.emplace_back(NewV);
-      }
-    }
-    else if (ETy == Type::getInt16Ty(M.getContext())) {
-      // This case only applies to typed buffer since Store operation of byte
-      // address buffer for min precision is handled by implicit conversion on
-      // intrinsic call. Since we are extending integer, we have to know if we
-      // should sign ext or zero ext. We can do this by iterating checking the
-      // size of the element at struct type and comp type at type annotation
-      CallInst *handleCI = dyn_cast<CallInst>(CI->getArgOperand(1));
-      DXASSERT(handleCI, "otherwise handle was not an argument to buffer store.");
-      ConstantInt *resClass = dyn_cast<ConstantInt>(handleCI->getArgOperand(1));
-      DXASSERT_LOCALVAR(resClass, resClass && resClass->getSExtValue() ==
-                               (unsigned)DXIL::ResourceClass::UAV,
-               "otherwise buffer store called on non uav kind.");
-      ConstantInt *rangeID = dyn_cast<ConstantInt>(handleCI->getArgOperand(2)); // range id or idx?
-      DXASSERT(rangeID, "wrong createHandle call.");
-      DxilResource dxilRes = M.GetDxilModule().GetUAV(rangeID->getSExtValue());
-      StructType *STy = dyn_cast<StructType>(dxilRes.GetRetType());
-      DxilStructAnnotation *SAnnot = M.GetDxilModule().GetTypeSystem().GetStructAnnotation(STy);
-      ConstantInt *offsetInt = dyn_cast<ConstantInt>(CI->getArgOperand(3));
-      unsigned offset = offsetInt->getSExtValue();
-      unsigned currentOffset = 0;
-      for (DxilStructTypeIterator iter = begin(STy, SAnnot), ItEnd = end(STy, SAnnot); iter != ItEnd; ++iter) {
-        std::pair<Type *, DxilFieldAnnotation*> pair = *iter;
-        currentOffset += M.getDataLayout().getTypeAllocSize(pair.first);
-        if (currentOffset > offset) {
-          if (pair.second->GetCompType().IsUIntTy()) {
-            for (unsigned i = 4; i < 8; ++i) {
-              Value *NewV = CIBuilder.CreateZExt(CI->getArgOperand(i), Type::getInt32Ty(M.getContext()));
-              Args.emplace_back(NewV);
-            }
-            break;
-          }
-          else if (pair.second->GetCompType().IsIntTy()) {
-            for (unsigned i = 4; i < 8; ++i) {
-              Value *NewV = CIBuilder.CreateSExt(CI->getArgOperand(i), Type::getInt32Ty(M.getContext()));
-              Args.emplace_back(NewV);
-            }
-            break;
-          }
-          else {
-            DXASSERT(false, "Invalid comp type");
-          }
-        }
-      }
-    }
-
-    // mask
-    Args.emplace_back(CI->getArgOperand(8));
-    // alignment
-    Args.emplace_back(M.GetDxilModule().GetOP()->GetI32Const(
-        M.getDataLayout().getTypeAllocSize(NewETy)));
-    CIBuilder.CreateCall(newFunction, Args);
-    CI->eraseFromParent();
-   }
-}
-
-
-void DxilTranslateRawBuffer::ReplaceMinPrecisionRawBufferLoadByType(
-    Function *F, Type *FromTy, Type *ToTy, OP *Op, const DataLayout &DL) {
-  Function *newFunction = Op->GetOpFunc(DXIL::OpCode::RawBufferLoad, ToTy);
-  for (auto FUser = F->user_begin(), FEnd = F->user_end(); FUser != FEnd;) {
-    User *UserCI = *(FUser++);
-    if (CallInst *CI = dyn_cast<CallInst>(UserCI)) {
-      IRBuilder<> CIBuilder(CI);
-      SmallVector<Value *, 5> newFuncArgs;
-      // opcode, handle, index, elementOffset, mask
-      // Compiler is generating correct element offset even for min precision types
-      // So no need to recalculate here
-      for (unsigned i = 0; i < 5; ++i) {
-        newFuncArgs.emplace_back(CI->getArgOperand(i));
-      }
-      // new alignment for new type
-      newFuncArgs.emplace_back(Op->GetI32Const(DL.getTypeAllocSize(ToTy)));
-      CallInst *newCI = CIBuilder.CreateCall(newFunction, newFuncArgs);
-      for (auto CIUser = CI->user_begin(), CIEnd = CI->user_end();
-           CIUser != CIEnd;) {
-        User *UserEV = *(CIUser++);
-        if (ExtractValueInst *EV = dyn_cast<ExtractValueInst>(UserEV)) {
-          IRBuilder<> EVBuilder(EV);
-          ArrayRef<unsigned> Indices = EV->getIndices();
-          DXASSERT(Indices.size() == 1, "Otherwise we have wrong extract value.");
-          Value *newEV = EVBuilder.CreateExtractValue(newCI, Indices);
-          Value *newTruncV = nullptr;
-          if (4 == Indices[0]) { // Don't truncate status
-            newTruncV = newEV;
-          }
-          else if (FromTy->isHalfTy()) {
-            newTruncV = EVBuilder.CreateFPTrunc(newEV, FromTy);
-          } else if (FromTy->isIntegerTy()) {
-            newTruncV = EVBuilder.CreateTrunc(newEV, FromTy);
-          } else {
-            DXASSERT(false, "unexpected type conversion");
-          }
-          EV->replaceAllUsesWith(newTruncV);
-          EV->eraseFromParent();
-        }
-      }
-      CI->eraseFromParent();
-    }
-  }
-  F->eraseFromParent();
-}
-
 char DxilTranslateRawBuffer::ID = 0;
 ModulePass *llvm::createDxilTranslateRawBuffer() {
   return new DxilTranslateRawBuffer();

+ 112 - 99
lib/HLSL/DxilValidation.cpp

@@ -26,6 +26,7 @@
 #include "dxc/DXIL/DxilInstructions.h"
 #include "llvm/Analysis/ReducibilityAnalysis.h"
 #include "dxc/DXIL/DxilEntryProps.h"
+#include "dxc/DXIL/DxilResourceProperties.h"
 
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/Analysis/CallGraph.h"
@@ -404,8 +405,9 @@ struct ValidationContext {
   std::unordered_set<Function *> entryFuncCallSet;
   std::unordered_set<Function *> patchConstFuncCallSet;
   std::unordered_map<unsigned, bool> UavCounterIncMap;
+  std::unordered_map<Value *, unsigned> HandleResIndexMap;
   // TODO: save resource map for each createHandle/createHandleForLib.
-  std::unordered_map<Value *, DxilResourceBase *> ResMap;
+  std::unordered_map<Value *, DxilResourceProperties> ResPropMap;
   std::unordered_map<Function *, std::vector<Function*>> PatchConstantFuncMap;
   std::unordered_map<Function *, std::unique_ptr<EntryStatus>> entryStatusMap;
   bool isLibProfile;
@@ -466,13 +468,16 @@ struct ValidationContext {
   }
 
   void PropagateResMap(Value *V, DxilResourceBase *Res) {
-    auto it = ResMap.find(V);
-    if (it != ResMap.end()) {
-      if (it->second != Res) {
+    auto it = ResPropMap.find(V);
+    if (it != ResPropMap.end()) {
+      DxilResourceProperties RP = resource_helper::loadFromResourceBase(Res);
+      DxilResourceProperties itRP = it->second;
+      if (itRP != RP) {
         EmitError(ValidationRule::InstrResourceMapToSingleEntry);
       }
     } else {
-      ResMap[V] = Res;
+      DxilResourceProperties RP = resource_helper::loadFromResourceBase(Res);
+      ResPropMap[V] = RP;
       for (User *U : V->users()) {
         if (GEPOperator *GEP = dyn_cast<GEPOperator>(U)) {
           PropagateResMap(U, Res);
@@ -480,7 +485,9 @@ struct ValidationContext {
           // Stop propagate on function call.
           DxilInst_CreateHandleForLib hdl(CI);
           if (hdl) {
-            ResMap[CI] = Res;
+            DxilResourceProperties RP =
+                resource_helper::loadFromResourceBase(Res);
+            ResPropMap[CI] = RP;
           }
         } else if (LoadInst *LI = dyn_cast<LoadInst>(U)) {
           PropagateResMap(U, Res);
@@ -591,9 +598,39 @@ struct ValidationContext {
               continue;
             }
           }
+          HandleResIndexMap[CI] = rangeId;
+          DxilResourceProperties RP = resource_helper::loadFromResourceBase(Res);
+          ResPropMap[CI] = RP;
+        }
+      }
+    }
+    Type *ResPropTy = hlslOP->GetResourcePropertiesType();
+    const ShaderModel &SM = *DxilMod.GetShaderModel();
 
-          ResMap[CI] = Res;
+    for (auto &it : hlslOP->GetOpFuncList(DXIL::OpCode::AnnotateHandle)) {
+      Function *F = it.second;
+      if (!F)
+        continue;
+
+      for (User *U : F->users()) {
+        CallInst *CI = cast<CallInst>(U);
+        DxilInst_AnnotateHandle hdl(CI);
+        // Validate Class/RangeID/Index.
+        Value *resClass = hdl.get_resourceClass();
+        if (!isa<ConstantInt>(resClass)) {
+          EmitInstrError(CI, ValidationRule::InstrOpConstRange);
+          continue;
         }
+
+        Value *resKind = hdl.get_resourceKind();
+        if (!isa<ConstantInt>(resKind)) {
+          EmitInstrError(CI, ValidationRule::InstrOpConstRange);
+          continue;
+        }
+
+        DxilResourceProperties RP =
+            resource_helper::loadFromAnnotateHandle(hdl, ResPropTy, SM);
+        ResPropMap[CI] = RP;
       }
     }
   }
@@ -604,7 +641,7 @@ struct ValidationContext {
 
   EntryStatus &GetEntryStatus(Function *F) { return *entryStatusMap[F]; }
 
-  DxilResourceBase *GetResourceFromVal(Value *resVal);
+  DxilResourceProperties GetResourceFromVal(Value *resVal);
 
   // Provide direct access to the raw_ostream in DiagPrinter.
   raw_ostream &DiagStream() {
@@ -955,6 +992,9 @@ static bool ValidateOpcodeInProfile(DXIL::OpCode opcode,
   if ((168 <= op && op <= 172))
     return (major > 6 || (major == 6 && minor >= 5))
         && (SK == DXIL::ShaderKind::Mesh);
+  // Instructions: CreateHandleFromHeap=216, AnnotateHandle=217
+  if ((216 <= op && op <= 217))
+    return (major > 6 || (major == 6 && minor >= 6));
   return true;
   // VALOPCODESM-TEXT:END
 }
@@ -1029,23 +1069,26 @@ static DXIL::SamplerKind GetSamplerKind(Value *samplerHandle,
     return DXIL::SamplerKind::Invalid;
   }
 
-  DxilResourceBase *Res = ValCtx.GetResourceFromVal(samplerHandle);
-  if (!Res) {
+  DxilResourceProperties RP = ValCtx.GetResourceFromVal(samplerHandle);
+  if (RP.Class == DXIL::ResourceClass::Invalid) {
       ValCtx.EmitInstrError(cast<CallInst>(samplerHandle),
           ValidationRule::InstrHandleNotFromCreateHandle);
       return DXIL::SamplerKind::Invalid;
   }
 
-  if (Res->GetClass() != DXIL::ResourceClass::Sampler) {
+  if (RP.Class != DXIL::ResourceClass::Sampler) {
     // must be sampler.
     return DXIL::SamplerKind::Invalid;
   }
-
-  return ((DxilSampler*)Res)->GetSamplerKind();
+  if (RP.Kind == DXIL::ResourceKind::SamplerComparison)
+    return DXIL::SamplerKind::Comparison;
+  else if (RP.Kind == DXIL::ResourceKind::Invalid)
+    return DXIL::SamplerKind::Invalid;
+  else
+    return DXIL::SamplerKind::Default;
 }
 
 static DXIL::ResourceKind GetResourceKindAndCompTy(Value *handle, DXIL::ComponentType &CompTy, DXIL::ResourceClass &ResClass,
-    unsigned &resIndex,
     ValidationContext &ValCtx) {
   CompTy = DXIL::ComponentType::Invalid;
   ResClass = DXIL::ResourceClass::Invalid;
@@ -1055,14 +1098,14 @@ static DXIL::ResourceKind GetResourceKindAndCompTy(Value *handle, DXIL::Componen
   }
   // TODO: validate ROV is used only in PS.
 
-  DxilResourceBase *Res = ValCtx.GetResourceFromVal(handle);
-  if (!Res) {
+  DxilResourceProperties RP = ValCtx.GetResourceFromVal(handle);
+  if (RP.Class == DXIL::ResourceClass::Invalid) {
     ValCtx.EmitInstrError(cast<CallInst>(handle),
                           ValidationRule::InstrHandleNotFromCreateHandle);
     return DXIL::ResourceKind::Invalid;
   }
 
-  ResClass = Res->GetClass();
+  ResClass = RP.Class;
 
   switch (ResClass) {
   case DXIL::ResourceClass::SRV:
@@ -1076,12 +1119,12 @@ static DXIL::ResourceKind GetResourceKindAndCompTy(Value *handle, DXIL::Componen
     // Emit invalid res class
     return DXIL::ResourceKind::Invalid;
   }
+  if (!DXIL::IsStructuredBuffer(RP.Kind))
+    CompTy = RP.Typed.CompType;
+  else
+    CompTy = DXIL::ComponentType::Invalid;
 
-  resIndex = Res->GetID();
-
-  CompTy = ((DxilResource*)Res)->GetCompType().GetKind();
-
-  return Res->GetKind();
+  return RP.Kind;
 }
 
 DxilFieldAnnotation *GetFieldAnnotation(Type *Ty,
@@ -1114,43 +1157,16 @@ DxilFieldAnnotation *GetFieldAnnotation(Type *Ty,
 }
 
 
-DxilResourceBase *ValidationContext::GetResourceFromVal(Value *resVal) {
-  auto it = ResMap.find(resVal);
-  if (it != ResMap.end())
+DxilResourceProperties ValidationContext::GetResourceFromVal(Value *resVal) {
+  auto it = ResPropMap.find(resVal);
+  if (it != ResPropMap.end()) {
     return it->second;
-  else
-    return nullptr;
-}
-
-static DxilResource *GetResource(Value *handle, ValidationContext &ValCtx) {
-  if (!isa<CallInst>(handle)) {
-    ValCtx.EmitError(ValidationRule::InstrHandleNotFromCreateHandle);
-    return nullptr;
-  }
-
-  DxilResourceBase *Res = ValCtx.GetResourceFromVal(handle);
-  if (!Res) {
-    ValCtx.EmitInstrError(cast<CallInst>(handle),
-                          ValidationRule::InstrHandleNotFromCreateHandle);
-    return nullptr;
   }
-
-  DXIL::ResourceClass ResClass = Res->GetClass();
-
-  switch (ResClass) {
-  case DXIL::ResourceClass::SRV:
-  case DXIL::ResourceClass::UAV:
-    break;
-  case DXIL::ResourceClass::CBuffer:
-    return nullptr;
-  case DXIL::ResourceClass::Sampler:
-    return nullptr;
-  default:
-    // Emit invalid res class
-    return nullptr;
+  else {
+    DxilResourceProperties RP;
+    RP.Class = DXIL::ResourceClass::Invalid;
+    return RP;
   }
-
-  return (DxilResource *)Res;
 }
 
 struct ResRetUsage {
@@ -1292,9 +1308,8 @@ static void ValidateSampleInst(CallInst *CI, Value *srvHandle, Value *samplerHan
 
   DXIL::ComponentType compTy;
   DXIL::ResourceClass resClass;
-  unsigned resIndex;
   DXIL::ResourceKind resKind =
-      GetResourceKindAndCompTy(srvHandle, compTy, resClass, resIndex, ValCtx);
+      GetResourceKindAndCompTy(srvHandle, compTy, resClass, ValCtx);
   bool isSampleCompTy = compTy == DXIL::ComponentType::F32;
   isSampleCompTy |= compTy == DXIL::ComponentType::SNormF32;
   isSampleCompTy |= compTy == DXIL::ComponentType::UNormF32;
@@ -1356,9 +1371,8 @@ static void ValidateGather(CallInst *CI, Value *srvHandle, Value *samplerHandle,
 
   DXIL::ComponentType compTy;
   DXIL::ResourceClass resClass;
-  unsigned resIndex;
   DXIL::ResourceKind resKind =
-      GetResourceKindAndCompTy(srvHandle, compTy, resClass, resIndex, ValCtx);
+      GetResourceKindAndCompTy(srvHandle, compTy, resClass, ValCtx);
 
   if (resClass != DXIL::ResourceClass::SRV) {
     ValCtx.EmitInstrError(CI, ValidationRule::InstrResourceClassForSamplerGather);
@@ -1410,20 +1424,20 @@ static int GetCBufSize(Value *cbHandle, ValidationContext &ValCtx) {
     return -1;
   }
 
-  DxilResourceBase *Res = ValCtx.GetResourceFromVal(cbHandle);
-  if (!Res) {
+  DxilResourceProperties RP = ValCtx.GetResourceFromVal(cbHandle);
+  if (RP.Class == DXIL::ResourceClass::Invalid) {
     ValCtx.EmitInstrError(cast<CallInst>(cbHandle),
                           ValidationRule::InstrHandleNotFromCreateHandle);
     return -1;
   }
 
-  if (Res->GetClass() != DXIL::ResourceClass::CBuffer) {
+  if (RP.Class != DXIL::ResourceClass::CBuffer) {
     ValCtx.EmitInstrError(cast<CallInst>(cbHandle),
                           ValidationRule::InstrCBufferClassForCBufferHandle);
     return -1;
   }
 
-  return ((DxilCBuffer *)Res)->GetSize();
+  return RP.SizeInBytes;
 }
 
 static unsigned GetNumVertices(DXIL::InputPrimitive inputPrimitive) {
@@ -1801,9 +1815,8 @@ static void ValidateResourceDxilOp(CallInst *CI, DXIL::OpCode opcode,
     Value *handle = getDim.get_handle();
     DXIL::ComponentType compTy;
     DXIL::ResourceClass resClass;
-    unsigned resIndex;
     DXIL::ResourceKind resKind =
-        GetResourceKindAndCompTy(handle, compTy, resClass, resIndex, ValCtx);
+        GetResourceKindAndCompTy(handle, compTy, resClass, ValCtx);
 
     // Check the result component use.
     ResRetUsage usage;
@@ -1860,6 +1873,7 @@ static void ValidateResourceDxilOp(CallInst *CI, DXIL::OpCode opcode,
     case DXIL::ResourceKind::TextureCubeArray:
       break;
     case DXIL::ResourceKind::StructuredBuffer:
+    case DXIL::ResourceKind::StructuredBufferWithCounter:
     case DXIL::ResourceKind::RawBuffer:
     case DXIL::ResourceKind::TypedBuffer:
     case DXIL::ResourceKind::TBuffer: {
@@ -1895,9 +1909,8 @@ static void ValidateResourceDxilOp(CallInst *CI, DXIL::OpCode opcode,
     Value *handle = lod.get_handle();
     DXIL::ComponentType compTy;
     DXIL::ResourceClass resClass;
-    unsigned resIndex;
     DXIL::ResourceKind resKind =
-        GetResourceKindAndCompTy(handle, compTy, resClass, resIndex, ValCtx);
+        GetResourceKindAndCompTy(handle, compTy, resClass,  ValCtx);
     if (resClass != DXIL::ResourceClass::SRV) {
       ValCtx.EmitInstrError(CI,
                             ValidationRule::InstrResourceClassForSamplerGather);
@@ -2025,9 +2038,8 @@ static void ValidateResourceDxilOp(CallInst *CI, DXIL::OpCode opcode,
     DxilInst_BufferStore bufSt(CI);
     DXIL::ComponentType compTy;
     DXIL::ResourceClass resClass;
-    unsigned resIndex;
     DXIL::ResourceKind resKind = GetResourceKindAndCompTy(
-        bufSt.get_uav(), compTy, resClass, resIndex, ValCtx);
+        bufSt.get_uav(), compTy, resClass,  ValCtx);
 
     if (resClass != DXIL::ResourceClass::UAV) {
       ValCtx.EmitInstrError(CI, ValidationRule::InstrResourceClassForUAVStore);
@@ -2073,6 +2085,7 @@ static void ValidateResourceDxilOp(CallInst *CI, DXIL::OpCode opcode,
       }
       break;
     case DXIL::ResourceKind::StructuredBuffer:
+    case DXIL::ResourceKind::StructuredBufferWithCounter:
       if (isa<UndefValue>(offset)) {
         ValCtx.EmitInstrError(CI,
                               ValidationRule::InstrCoordinateCountForStructBuf);
@@ -2089,9 +2102,8 @@ static void ValidateResourceDxilOp(CallInst *CI, DXIL::OpCode opcode,
     DxilInst_TextureStore texSt(CI);
     DXIL::ComponentType compTy;
     DXIL::ResourceClass resClass;
-    unsigned resIndex;
     DXIL::ResourceKind resKind = GetResourceKindAndCompTy(
-        texSt.get_srv(), compTy, resClass, resIndex, ValCtx);
+        texSt.get_srv(), compTy, resClass,  ValCtx);
 
     if (resClass != DXIL::ResourceClass::UAV) {
       ValCtx.EmitInstrError(CI, ValidationRule::InstrResourceClassForUAVStore);
@@ -2136,9 +2148,8 @@ static void ValidateResourceDxilOp(CallInst *CI, DXIL::OpCode opcode,
     DxilInst_BufferLoad bufLd(CI);
     DXIL::ComponentType compTy;
     DXIL::ResourceClass resClass;
-    unsigned resIndex;
     DXIL::ResourceKind resKind = GetResourceKindAndCompTy(
-        bufLd.get_srv(), compTy, resClass, resIndex, ValCtx);
+        bufLd.get_srv(), compTy, resClass,  ValCtx);
 
     if (resClass != DXIL::ResourceClass::SRV &&
         resClass != DXIL::ResourceClass::UAV) {
@@ -2157,6 +2168,7 @@ static void ValidateResourceDxilOp(CallInst *CI, DXIL::OpCode opcode,
       }
       break;
     case DXIL::ResourceKind::StructuredBuffer:
+    case DXIL::ResourceKind::StructuredBufferWithCounter:
       if (isa<UndefValue>(offset)) {
         ValCtx.EmitInstrError(CI,
                               ValidationRule::InstrCoordinateCountForStructBuf);
@@ -2173,9 +2185,8 @@ static void ValidateResourceDxilOp(CallInst *CI, DXIL::OpCode opcode,
     DxilInst_TextureLoad texLd(CI);
     DXIL::ComponentType compTy;
     DXIL::ResourceClass resClass;
-    unsigned resIndex;
     DXIL::ResourceKind resKind = GetResourceKindAndCompTy(
-        texLd.get_srv(), compTy, resClass, resIndex, ValCtx);
+        texLd.get_srv(), compTy, resClass,  ValCtx);
 
     Value *mipLevel = texLd.get_mipLevelOrSampleCount();
 
@@ -2248,9 +2259,8 @@ static void ValidateResourceDxilOp(CallInst *CI, DXIL::OpCode opcode,
     DxilInst_RawBufferLoad bufLd(CI);
     DXIL::ComponentType compTy;
     DXIL::ResourceClass resClass;
-    unsigned resIndex;
     DXIL::ResourceKind resKind = GetResourceKindAndCompTy(
-        bufLd.get_srv(), compTy, resClass, resIndex, ValCtx);
+        bufLd.get_srv(), compTy, resClass,  ValCtx);
 
     if (resClass != DXIL::ResourceClass::SRV &&
         resClass != DXIL::ResourceClass::UAV) {
@@ -2274,6 +2284,7 @@ static void ValidateResourceDxilOp(CallInst *CI, DXIL::OpCode opcode,
       }
       break;
     case DXIL::ResourceKind::StructuredBuffer:
+    case DXIL::ResourceKind::StructuredBufferWithCounter:
       if (isa<UndefValue>(offset)) {
         ValCtx.EmitInstrError(CI,
                               ValidationRule::InstrCoordinateCountForStructBuf);
@@ -2297,9 +2308,8 @@ static void ValidateResourceDxilOp(CallInst *CI, DXIL::OpCode opcode,
     DxilInst_RawBufferStore bufSt(CI);
     DXIL::ComponentType compTy;
     DXIL::ResourceClass resClass;
-    unsigned resIndex;
     DXIL::ResourceKind resKind = GetResourceKindAndCompTy(
-        bufSt.get_uav(), compTy, resClass, resIndex, ValCtx);
+        bufSt.get_uav(), compTy, resClass,  ValCtx);
 
     if (resClass != DXIL::ResourceClass::UAV) {
       ValCtx.EmitInstrError(CI, ValidationRule::InstrResourceClassForUAVStore);
@@ -2340,6 +2350,7 @@ static void ValidateResourceDxilOp(CallInst *CI, DXIL::OpCode opcode,
       }
       break;
     case DXIL::ResourceKind::StructuredBuffer:
+    case DXIL::ResourceKind::StructuredBufferWithCounter:
       if (isa<UndefValue>(offset)) {
         ValCtx.EmitInstrError(CI,
                               ValidationRule::InstrCoordinateCountForStructBuf);
@@ -2354,12 +2365,12 @@ static void ValidateResourceDxilOp(CallInst *CI, DXIL::OpCode opcode,
   case DXIL::OpCode::TraceRay: {
     DxilInst_TraceRay traceRay(CI);
     Value *hdl = traceRay.get_AccelerationStructure();
-    DxilResourceBase *Res = ValCtx.GetResourceFromVal(hdl);
-    if (!Res) {
+    DxilResourceProperties RP = ValCtx.GetResourceFromVal(hdl);
+    if (RP.Class == DXIL::ResourceClass::Invalid) {
       ValCtx.EmitInstrError(CI, ValidationRule::InstrResourceKindForTraceRay);
       return;
     }
-    if (Res->GetKind() != DXIL::ResourceKind::RTAccelerationStructure) {
+    if (RP.Kind != DXIL::ResourceKind::RTAccelerationStructure) {
       ValCtx.EmitInstrError(CI, ValidationRule::InstrResourceKindForTraceRay);
     }
   } break;
@@ -2445,23 +2456,19 @@ static void ValidateDxilOperationCallInProfile(CallInst *CI,
   // Special.
   case DXIL::OpCode::BufferUpdateCounter: {
     DxilInst_BufferUpdateCounter updateCounter(CI);
-    DxilResource *res = GetResource(updateCounter.get_uav(), ValCtx);
-
-    if (!res) {
-      return;
-    }
+    Value *handle = updateCounter.get_uav();
+    DxilResourceProperties RP = ValCtx.GetResourceFromVal(handle);
 
-    if (res->GetClass() != DXIL::ResourceClass::UAV) {
+    if (RP.Class != DXIL::ResourceClass::UAV) {
       ValCtx.EmitInstrError(CI,
                                ValidationRule::InstrBufferUpdateCounterOnUAV);
     }
 
-    if (res->GetKind() != DXIL::ResourceKind::StructuredBuffer) {
-      ValCtx.EmitInstrError(CI,
-                               ValidationRule::SmCounterOnlyOnStructBuf);
+    if (!DXIL::IsStructuredBuffer(RP.Kind)) {
+      ValCtx.EmitInstrError(CI, ValidationRule::SmCounterOnlyOnStructBuf);
     }
 
-    if (!res->HasCounter()) {
+    if (RP.Kind != DXIL::ResourceKind::StructuredBufferWithCounter) {
       ValCtx.EmitInstrError(
           CI, ValidationRule::InstrBufferUpdateCounterOnResHasCounter);
     }
@@ -2470,14 +2477,19 @@ static void ValidateDxilOperationCallInProfile(CallInst *CI,
     if (ConstantInt *cInc = dyn_cast<ConstantInt>(inc)) {
       bool isInc = cInc->getLimitedValue() == 1;
       if (!ValCtx.isLibProfile) {
-        unsigned resIndex = res->GetLowerBound();
-        if (ValCtx.UavCounterIncMap.count(resIndex)) {
-          if (isInc != ValCtx.UavCounterIncMap[resIndex]) {
-            ValCtx.EmitInstrError(CI, ValidationRule::InstrOnlyOneAllocConsume);
+        auto it = ValCtx.HandleResIndexMap.find(handle);
+        if (it != ValCtx.HandleResIndexMap.end()) {
+          unsigned resIndex = it->second;
+          if (ValCtx.UavCounterIncMap.count(resIndex)) {
+            if (isInc != ValCtx.UavCounterIncMap[resIndex]) {
+              ValCtx.EmitInstrError(CI,
+                                    ValidationRule::InstrOnlyOneAllocConsume);
+            }
+          } else {
+            ValCtx.UavCounterIncMap[resIndex] = isInc;
           }
-        } else {
-          ValCtx.UavCounterIncMap[resIndex] = isInc;
         }
+
       } else {
         // TODO: validate ValidationRule::InstrOnlyOneAllocConsume for lib
         // profile.
@@ -3925,6 +3937,7 @@ static void ValidateResource(hlsl::DxilResource &res,
   case DXIL::ResourceKind::TypedBuffer:
   case DXIL::ResourceKind::TBuffer:
   case DXIL::ResourceKind::StructuredBuffer:
+  case DXIL::ResourceKind::StructuredBufferWithCounter:
   case DXIL::ResourceKind::Texture1D:
   case DXIL::ResourceKind::Texture1DArray:
   case DXIL::ResourceKind::Texture2D:

+ 6 - 0
lib/HLSL/HLModule.cpp

@@ -756,6 +756,12 @@ MDNode *HLModule::DxilCBufferToMDNode(const DxilCBuffer &CB) {
 void HLModule::LoadDxilResourceBaseFromMDNode(MDNode *MD, DxilResourceBase &R) {
   return m_pMDHelper->LoadDxilResourceBaseFromMDNode(MD, R);
 }
+void HLModule::LoadDxilResourceFromMDNode(llvm::MDNode *MD, DxilResource &R) {
+  return m_pMDHelper->LoadDxilResourceFromMDNode(MD, R);
+}
+void HLModule::LoadDxilSamplerFromMDNode(llvm::MDNode *MD, DxilSampler &S) {
+  return m_pMDHelper->LoadDxilSamplerFromMDNode(MD, S);
+}
 
 DxilResourceBase *HLModule::AddResourceWithGlobalVariableAndMDNode(llvm::Constant *GV,
                                                       llvm::MDNode *MD) {

+ 59 - 4
lib/HLSL/HLOperationLower.cpp

@@ -26,6 +26,7 @@
 #include "dxc/HLSL/HLOperations.h"
 #include "dxc/HlslIntrinsicOp.h"
 #include "dxc/HLSL/DxilConvergent.h"
+#include "dxc/DXIL/DxilResourceProperties.h"
 
 #include "llvm/IR/GetElementPtrTypeIterator.h"
 #include "llvm/IR/IRBuilder.h"
@@ -159,6 +160,26 @@ private:
     HandleMetaMap[Handle] = {DXIL::ResourceClass::Invalid,
                              DXIL::ResourceKind::Invalid,
                              StructType::get(Type::getVoidTy(HLM.GetCtx()), nullptr)};
+    if (CallInst *CI = dyn_cast<CallInst>(Handle)) {
+      hlsl::HLOpcodeGroup group =
+          hlsl::GetHLOpcodeGroupByName(CI->getCalledFunction());
+      if (group == HLOpcodeGroup::HLAnnotateHandle) {
+        ConstantInt *RC = cast<ConstantInt>(CI->getArgOperand(
+            HLOperandIndex::kAnnotateHandleResourceClassOpIdx));
+        ConstantInt *RK = cast<ConstantInt>(CI->getArgOperand(
+            HLOperandIndex::kAnnotateHandleResourceKindOpIdx));
+        Type *ResTy =
+            CI->getArgOperand(HLOperandIndex::kAnnotateHandleResourceTypeOpIdx)
+                ->getType();
+
+        ResAttribute Attrib = {(DXIL::ResourceClass)RC->getLimitedValue(),
+                               (DXIL::ResourceKind)RK->getLimitedValue(),
+                               ResTy};
+
+        HandleMetaMap[Handle] = Attrib;
+        return HandleMetaMap[Handle];
+      }
+    }
     if (Argument *Arg = dyn_cast<Argument>(Handle)) {
       MDNode *MD = HLM.GetDxilResourceAttrib(Arg);
       if (!MD) {
@@ -2485,7 +2506,7 @@ Value *TranslateGetDimensions(CallInst *CI, IntrinsicOp IOP, OP::OpCode op,
 
   Builder.CreateStore(width, widthPtr);
 
-  if (RK == DxilResource::Kind::StructuredBuffer) {
+  if (DXIL::IsStructuredBuffer(RK)) {
     // Set stride.
     Value *stridePtr = CI->getArgOperand(widthOpIdx + 1);
     const DataLayout &DL = helper.dataLayout;
@@ -2535,7 +2556,23 @@ Value *GenerateUpdateCounter(CallInst *CI, IntrinsicOp IOP, OP::OpCode opcode,
                              HLOperationLowerHelper &helper,  HLObjectOperationLowerHelper *pObjHelper, bool &Translated) {
   hlsl::OP *hlslOP = &helper.hlslOP;
   Value *handle = CI->getArgOperand(HLOperandIndex::kHandleOpIdx);
-  pObjHelper->MarkHasCounter(handle->getType(), handle);
+  Value *counterHandle = handle;
+  if (CallInst *CIHandle = dyn_cast<CallInst>(handle)) {
+    hlsl::HLOpcodeGroup group =
+        hlsl::GetHLOpcodeGroup(CIHandle->getCalledFunction());
+    if (group == HLOpcodeGroup::HLAnnotateHandle) {
+      // Mark has counter for the input handle.
+      counterHandle =
+          CIHandle->getArgOperand(HLOperandIndex::kAnnotateHandleHandleOpIdx);
+      // Change kind into StructurBufferWithCounter.
+      CIHandle->setArgOperand(
+          HLOperandIndex::kAnnotateHandleResourceKindOpIdx,
+          ConstantInt::get(
+              helper.i8Ty,
+              (unsigned)DXIL::ResourceKind::StructuredBufferWithCounter));
+    }
+  }
+  pObjHelper->MarkHasCounter(counterHandle->getType(), counterHandle);
 
   bool bInc = IOP == IntrinsicOp::MOP_IncrementCounter;
   IRBuilder<> Builder(CI);
@@ -3427,6 +3464,7 @@ ResLoadHelper::ResLoadHelper(CallInst *CI, DxilResource::Kind RK,
   switch (RK) {
   case DxilResource::Kind::RawBuffer:
   case DxilResource::Kind::StructuredBuffer:
+  case DxilResource::Kind::StructuredBufferWithCounter:
     opcode = OP::OpCode::RawBufferLoad;
     break;
   case DxilResource::Kind::TypedBuffer:
@@ -3603,7 +3641,7 @@ void TranslateLoad(ResLoadHelper &helper, HLResource::Kind RK,
     numComponents = Ty->getVectorNumElements();
   }
 
-  if (RK == HLResource::Kind::StructuredBuffer) {
+  if (DXIL::IsStructuredBuffer(RK)) {
     // Basic type case for StructuredBuffer::Load()
     Value *ResultElts[4];
     Value *StructBufLoad = GenerateStructBufLd(helper.handle, helper.addr, OP->GetU32Const(0),
@@ -3797,6 +3835,7 @@ void TranslateStore(DxilResource::Kind RK, Value *handle, Value *val,
   switch (RK) {
   case DxilResource::Kind::RawBuffer:
   case DxilResource::Kind::StructuredBuffer:
+  case DxilResource::Kind::StructuredBufferWithCounter:
     opcode = OP::OpCode::RawBufferStore;
     break;
   case DxilResource::Kind::TypedBuffer:
@@ -5085,6 +5124,21 @@ Value *TranslateDot4AddPacked(CallInst *CI, IntrinsicOp IOP, OP::OpCode opcode,
 
 } // namespace
 
+// Resource Handle.
+namespace {
+Value *TranslateGetHandleFromHeap(CallInst *CI, IntrinsicOp IOP,
+                                  DXIL::OpCode opcode,
+                                  HLOperationLowerHelper &helper,
+                                  HLObjectOperationLowerHelper *pObjHelper,
+                                  bool &Translated) {
+  hlsl::OP &hlslOP = helper.hlslOP;
+  Function *dxilFunc = hlslOP.GetOpFunc(opcode, helper.voidTy);
+  IRBuilder<> Builder(CI);
+  Value *opArg = ConstantInt::get(helper.i32Ty, (unsigned)opcode);
+  return Builder.CreateCall(dxilFunc, {opArg, CI->getArgOperand(HLOperandIndex::kUnaryOpSrc0Idx)});
+}
+}
+
 // Lower table.
 namespace {
 
@@ -5140,6 +5194,7 @@ IntrinsicLower gLowerTable[] = {
     {IntrinsicOp::IOP_GetAttributeAtVertex, TranslateGetAttributeAtVertex, DXIL::OpCode::AttributeAtVertex},
     {IntrinsicOp::IOP_GetRenderTargetSampleCount, TrivialNoArgOperation, DXIL::OpCode::RenderTargetGetSampleCount},
     {IntrinsicOp::IOP_GetRenderTargetSamplePosition, TranslateGetRTSamplePos, DXIL::OpCode::NumOpCodes},
+    {IntrinsicOp::IOP_GetResourceFromHeap, TranslateGetHandleFromHeap, DXIL::OpCode::CreateHandleFromHeap},
     {IntrinsicOp::IOP_GroupMemoryBarrier, TrivialBarrier, DXIL::OpCode::Barrier},
     {IntrinsicOp::IOP_GroupMemoryBarrierWithGroupSync, TrivialBarrier, DXIL::OpCode::Barrier},
     {IntrinsicOp::IOP_HitKind, TrivialNoArgWithRetOperation, DXIL::OpCode::HitKind},
@@ -7450,7 +7505,7 @@ void TranslateHLSubscript(CallInst *CI, HLSubscriptOpcode opcode,
       Translated = true;
       Type *ObjTy = pObjHelper->GetResourceType(handle);
       Type *RetTy = ObjTy->getStructElementType(0);
-      if (RK == DxilResource::Kind::StructuredBuffer) {
+      if (DXIL::IsStructuredBuffer(RK)) {
         TranslateStructBufSubscript(CI, handle, /*status*/ nullptr, hlslOP, RK,
                                     helper.dataLayout);
       } else if (RetTy->isAggregateType() &&

+ 10 - 0
lib/HLSL/HLOperations.cpp

@@ -38,6 +38,7 @@ static StringRef HLOpcodeGroupNames[]{
     "matldst",     // HLMatLoadStore,
     "select",      // HLSelect,
     "createhandle",// HLCreateHandle,
+    "annotatehandle" // HLAnnotateHandle,
     "numOfHLDXIL", // NumOfHLOps
 };
 
@@ -53,6 +54,7 @@ static StringRef HLOpcodeGroupFullNames[]{
     "dx.hl.matldst",   // HLMatLoadStore,
     "dx.hl.select",    // HLSelect,
     "dx.hl.createhandle",  // HLCreateHandle,
+    "dx.hl.annotatehandle",      // HLAnnotateHandle,
     "numOfHLDXIL",     // NumOfHLOps
 };
 
@@ -83,6 +85,8 @@ static HLOpcodeGroup GetHLOpcodeGroupInternal(StringRef group) {
       }
     case 'm': // matldst
       return HLOpcodeGroup::HLMatLoadStore;
+    case 'a': // annotatehandle
+      return HLOpcodeGroup::HLAnnotateHandle;
     }
   }
   return HLOpcodeGroup::NotHL;
@@ -133,6 +137,7 @@ StringRef GetHLOpcodeGroupName(HLOpcodeGroup op) {
   case HLOpcodeGroup::HLMatLoadStore:
   case HLOpcodeGroup::HLSelect:
   case HLOpcodeGroup::HLCreateHandle:
+  case HLOpcodeGroup::HLAnnotateHandle:
     return HLOpcodeGroupNames[static_cast<unsigned>(op)];
   default:
     llvm_unreachable("invalid op");
@@ -151,6 +156,7 @@ StringRef GetHLOpcodeGroupFullName(HLOpcodeGroup op) {
   case HLOpcodeGroup::HLMatLoadStore:
   case HLOpcodeGroup::HLSelect:
   case HLOpcodeGroup::HLCreateHandle:
+  case HLOpcodeGroup::HLAnnotateHandle:
     return HLOpcodeGroupFullNames[static_cast<unsigned>(op)];
   default:
     llvm_unreachable("invalid op");
@@ -433,6 +439,10 @@ static void SetHLFunctionAttribute(Function *F, HLOpcodeGroup group,
     F->addFnAttr(Attribute::NoInline);
     F->setLinkage(llvm::GlobalValue::LinkageTypes::InternalLinkage);
   } break;
+  case HLOpcodeGroup::HLAnnotateHandle: {
+    F->addFnAttr(Attribute::ReadNone);
+    F->addFnAttr(Attribute::NoUnwind);
+  } break;
   case HLOpcodeGroup::NotHL:
   case HLOpcodeGroup::HLExtIntrinsic:
   case HLOpcodeGroup::HLIntrinsic:

+ 2 - 0
tools/clang/include/clang/AST/HlslTypes.h

@@ -323,6 +323,7 @@ clang::CXXRecordDecl* DeclareTemplateTypeWithHandle(
 clang::CXXRecordDecl* DeclareUIntTemplatedTypeWithHandle(
   clang::ASTContext& context, llvm::StringRef typeName, llvm::StringRef templateParamName);
 clang::CXXRecordDecl* DeclareRayQueryType(clang::ASTContext& context);
+clang::CXXRecordDecl *DeclareResourceType(clang::ASTContext &context);
 
 /// <summary>Create a function template declaration for the specified method.</summary>
 /// <param name="context">AST context in which to work.</param>
@@ -362,6 +363,7 @@ bool HasHLSLMatOrientation(clang::QualType type, bool *pIsRowMajor = nullptr);
 bool IsHLSLMatRowMajor(clang::QualType type, bool defaultValue);
 bool IsHLSLUnsigned(clang::QualType type);
 bool HasHLSLUNormSNorm(clang::QualType type, bool *pIsSNorm = nullptr);
+bool HasHLSLGloballyCoherent(clang::QualType type);
 bool IsHLSLInputPatchType(clang::QualType type);
 bool IsHLSLOutputPatchType(clang::QualType type);
 bool IsHLSLPointStreamType(clang::QualType type);

+ 2 - 1
tools/clang/include/clang/AST/Type.h

@@ -3650,7 +3650,8 @@ public:
     attr_hlsl_unorm,
     attr_hlsl_snorm,
     attr_hlsl_row_major,
-    attr_hlsl_column_major
+    attr_hlsl_column_major,
+    attr_hlsl_globallycoherent,
     // HLSL Change Ends    
   };
 

+ 4 - 4
tools/clang/include/clang/Sema/SemaHLSL.h

@@ -205,10 +205,10 @@ void CustomPrintHLSLAttr(const clang::Attr *A, llvm::raw_ostream &Out, const cla
 void PrintClipPlaneIfPresent(clang::Expr *ClipPlane, llvm::raw_ostream &Out, const clang::PrintingPolicy &Policy);
 void Indent(unsigned int Indentation, llvm::raw_ostream &Out);
 void GetHLSLAttributedTypes(
-  _In_ clang::Sema* self,
-  clang::QualType type, 
-  _Inout_opt_ const clang::AttributedType** ppMatrixOrientation, 
-  _Inout_opt_ const clang::AttributedType** ppNorm);
+    _In_ clang::Sema *self, clang::QualType type,
+    _Inout_opt_ const clang::AttributedType **ppMatrixOrientation,
+    _Inout_opt_ const clang::AttributedType **ppNorm,
+    _Inout_opt_ const clang::AttributedType **ppGLC);
 
 bool IsMatrixType(
   _In_ clang::Sema* self, 

+ 12 - 0
tools/clang/lib/AST/ASTContextHLSL.cpp

@@ -849,6 +849,18 @@ CXXRecordDecl* hlsl::DeclareRayQueryType(ASTContext& context) {
   return typeDeclBuilder.completeDefinition();
 }
 
+CXXRecordDecl* hlsl::DeclareResourceType(ASTContext& context) {
+  // struct ResourceDescriptor { uint8 desc; }
+  BuiltinTypeDeclBuilder typeDeclBuilder(context.getTranslationUnitDecl(),
+                                         ".Resource",
+                                         TagDecl::TagKind::TTK_Struct);
+  typeDeclBuilder.startDefinition();
+
+  typeDeclBuilder.addField("h", GetHLSLObjectHandleType(context));
+
+  return typeDeclBuilder.completeDefinition();
+}
+
 bool hlsl::IsIntrinsicOp(const clang::FunctionDecl *FD) {
   return FD != nullptr && FD->hasAttr<HLSLIntrinsicAttr>();
 }

+ 14 - 0
tools/clang/lib/AST/HlslTypes.cpp

@@ -223,6 +223,20 @@ bool HasHLSLUNormSNorm(clang::QualType type, bool *pIsSNorm) {
   return false;
 }
 
+bool HasHLSLGloballyCoherent(clang::QualType type) {
+  const AttributedType *AT = type->getAs<AttributedType>();
+  while (AT) {
+    AttributedType::Kind kind = AT->getAttrKind();
+    switch (kind) {
+    case AttributedType::attr_hlsl_globallycoherent:
+      return true;
+    }
+    AT = AT->getLocallyUnqualifiedSingleStepDesugaredType()
+             ->getAs<AttributedType>();
+  }
+  return false;
+}
+
 /// Checks whether the pAttributes indicate a parameter is inout or out; if
 /// inout, pIsIn will be set to true.
 bool IsParamAttributedAsOut(_In_opt_ clang::AttributeList *pAttributes,

+ 2 - 0
tools/clang/lib/AST/Type.cpp

@@ -2942,6 +2942,7 @@ bool AttributedType::isHLSLTypeSpec() const {
   case attr_hlsl_column_major:
   case attr_hlsl_snorm:
   case attr_hlsl_unorm:
+  case attr_hlsl_globallycoherent:
     return true;
   }
   llvm_unreachable("invalid attr kind");
@@ -2971,6 +2972,7 @@ bool AttributedType::isCallingConv() const {
   case attr_hlsl_column_major:
   case attr_hlsl_snorm:
   case attr_hlsl_unorm:
+  case attr_hlsl_globallycoherent:
   // HLSL Change Ends
     return false;
 

+ 3 - 0
tools/clang/lib/AST/TypePrinter.cpp

@@ -1159,6 +1159,9 @@ void TypePrinter::printAttributedBefore(const AttributedType *T,
     case AttributedType::attr_hlsl_column_major: OS << "column_major "; break;
     case AttributedType::attr_hlsl_unorm: OS << "unorm "; break;
     case AttributedType::attr_hlsl_snorm: OS << "snorm "; break;
+    case AttributedType::attr_hlsl_globallycoherent:
+      OS << "globallycoherent ";
+      break;
     default:
       // Only HLSL attribute types are covered.
       break;

+ 3 - 0
tools/clang/lib/CodeGen/CGCall.cpp

@@ -3270,6 +3270,9 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
     SRetPtr = ReturnValue.getValue();
     if (!SRetPtr) {
       SRetPtr = CreateMemTemp(RetTy);
+      // HLSL Change begin.
+      CGM.getHLSLRuntime().MarkRetTemp(*this, SRetPtr, RetTy);
+      // HLSL Change end.
       if (HaveInsertPoint() && ReturnValue.isUnused()) {
         uint64_t size =
             CGM.getDataLayout().getTypeAllocSize(ConvertTypeForMem(RetTy));

+ 295 - 20
tools/clang/lib/CodeGen/CGHLSLMS.cpp

@@ -47,6 +47,7 @@
 #include "dxc/HLSL/HLSLExtensionsCodegenHelper.h"
 #include "dxc/HLSL/DxilGenerationPass.h" // support pause/resume passes
 #include "dxc/HLSL/DxilExportMap.h"
+#include "dxc/DXIL/DxilResourceProperties.h"
 
 using namespace clang;
 using namespace CodeGen;
@@ -107,6 +108,11 @@ private:
                  llvm::SmallVector<std::pair<DXIL::ResourceClass, unsigned>, 1>>
       constantRegBindingMap;
 
+  // Map from value to resource properties.
+  // This only collect object variables(global/local/parameter), not object fields inside struct.
+  // Object fields inside struct is saved by TypeAnnotation.
+  DenseMap<Value *, DxilResourceProperties> valToResPropertiesMap;
+
   bool  m_bDebugInfo;
   bool  m_bIsLib;
 
@@ -228,6 +234,12 @@ private:
   // save intrinsic opcode
   std::vector<std::pair<Function *, unsigned>> m_IntrinsicMap;
   void AddHLSLIntrinsicOpcodeToFunction(Function *, unsigned opcode);
+  void AddOpcodeParamForIntrinsics(
+      HLModule &HLM, std::vector<std::pair<Function *, unsigned>> &intrinsicMap,
+      std::unordered_map<llvm::Type *, MDNode *> &resMetaMap);
+  void AddOpcodeParamForIntrinsic(
+      HLModule &HLM, Function *F, unsigned opcode, llvm::Type *HandleTy,
+      std::unordered_map<llvm::Type *, MDNode *> &resMetaMap);
 
   // Type annotation related.
   unsigned ConstructStructAnnotation(DxilStructAnnotation *annotation,
@@ -235,7 +247,8 @@ private:
                                      DxilTypeSystem &dxilTypeSys);
   unsigned AddTypeAnnotation(QualType Ty, DxilTypeSystem &dxilTypeSys,
                              unsigned &arrayEltSize);
-  MDNode *GetOrAddResTypeMD(QualType resTy);
+  MDNode *GetOrAddResTypeMD(QualType resTy, bool bCreate);
+  DxilResourceProperties BuildResourceProperty(QualType resTy);
   void ConstructFieldAttributedAnnotation(DxilFieldAnnotation &fieldAnnotation,
                                           QualType fieldTy,
                                           bool bDefaultRowMajor);
@@ -314,7 +327,8 @@ public:
   void AddControlFlowHint(CodeGenFunction &CGF, const Stmt &S,
                           llvm::TerminatorInst *TI,
                           ArrayRef<const Attr *> Attrs) override;
-  
+  void MarkRetTemp(CodeGenFunction &CGF, llvm::Value *V,
+                  clang::QualType QaulTy) override;
   void FinishAutoVar(CodeGenFunction &CGF, const VarDecl &D, llvm::Value *V) override;
 
   /// Get or add constant to the program
@@ -752,7 +766,7 @@ static DxilSampler::SamplerKind KeywordToSamplerKind(llvm::StringRef keyword) {
     .Default(DxilSampler::SamplerKind::Invalid);
 }
 
-MDNode *CGMSHLSLRuntime::GetOrAddResTypeMD(QualType resTy) {
+MDNode *CGMSHLSLRuntime::GetOrAddResTypeMD(QualType resTy, bool bCreate) {
   const RecordType *RT = resTy->getAs<RecordType>();
   if (!RT)
     return nullptr;
@@ -762,7 +776,7 @@ MDNode *CGMSHLSLRuntime::GetOrAddResTypeMD(QualType resTy) {
   hlsl::DxilResourceBase::Class resClass = TypeToClass(resTy);
   llvm::Type *Ty = CGM.getTypes().ConvertType(resTy);
   auto it = resMetadataMap.find(Ty);
-  if (it != resMetadataMap.end())
+  if (!bCreate && it != resMetadataMap.end())
     return it->second;
 
   // Save resource type metadata.
@@ -772,7 +786,7 @@ MDNode *CGMSHLSLRuntime::GetOrAddResTypeMD(QualType resTy) {
     // TODO: save globalcoherent to variable in EmitHLSLBuiltinCallExpr.
     SetUAVSRV(loc, resClass, &UAV, resTy);
     // Set global symbol to save type.
-    UAV.SetGlobalSymbol(UndefValue::get(Ty));
+    UAV.SetGlobalSymbol(UndefValue::get(Ty->getPointerTo()));
     MDNode *MD = m_pHLModule->DxilUAVToMDNode(UAV);
     resMetadataMap[Ty] = MD;
     return MD;
@@ -781,7 +795,7 @@ MDNode *CGMSHLSLRuntime::GetOrAddResTypeMD(QualType resTy) {
     DxilResource SRV;
     SetUAVSRV(loc, resClass, &SRV, resTy);
     // Set global symbol to save type.
-    SRV.SetGlobalSymbol(UndefValue::get(Ty));
+    SRV.SetGlobalSymbol(UndefValue::get(Ty->getPointerTo()));
     MDNode *MD = m_pHLModule->DxilSRVToMDNode(SRV);
     resMetadataMap[Ty] = MD;
     return MD;
@@ -791,7 +805,7 @@ MDNode *CGMSHLSLRuntime::GetOrAddResTypeMD(QualType resTy) {
     DxilSampler::SamplerKind kind = KeywordToSamplerKind(RD->getName());
     S.SetSamplerKind(kind);
     // Set global symbol to save type.
-    S.SetGlobalSymbol(UndefValue::get(Ty));
+    S.SetGlobalSymbol(UndefValue::get(Ty->getPointerTo()));
     MDNode *MD = m_pHLModule->DxilSamplerToMDNode(S);
     resMetadataMap[Ty] = MD;
     return MD;
@@ -802,16 +816,17 @@ MDNode *CGMSHLSLRuntime::GetOrAddResTypeMD(QualType resTy) {
   }
 }
 
+
 namespace {
 MatrixOrientation GetMatrixMajor(QualType Ty, bool bDefaultRowMajor) {
   DXASSERT(hlsl::IsHLSLMatType(Ty), "");
   bool bIsRowMajor = bDefaultRowMajor;
   HasHLSLMatOrientation(Ty, &bIsRowMajor);
   return bIsRowMajor ? MatrixOrientation::RowMajor
-                          : MatrixOrientation::ColumnMajor;
+                     : MatrixOrientation::ColumnMajor;
 }
 
-QualType GetArrayEltType(ASTContext& Context, QualType Ty) {
+QualType GetArrayEltType(ASTContext &Context, QualType Ty) {
   while (const clang::ArrayType *ArrayTy = Context.getAsArrayType(Ty))
     Ty = ArrayTy->getElementType();
   return Ty;
@@ -819,6 +834,51 @@ QualType GetArrayEltType(ASTContext& Context, QualType Ty) {
 
 } // namespace
 
+DxilResourceProperties CGMSHLSLRuntime::BuildResourceProperty(QualType resTy) {
+  resTy = GetArrayEltType(CGM.getContext(), resTy);
+  const RecordType *RT = resTy->getAs<RecordType>();
+  DxilResourceProperties RP;
+  if (!RT) {
+    RP.Class = DXIL::ResourceClass::Invalid;
+    return RP;
+  }
+  RecordDecl *RD = RT->getDecl();
+  SourceLocation loc = RD->getLocation();
+
+  hlsl::DxilResourceBase::Class resClass = TypeToClass(resTy);
+  RP.Class = resClass;
+  if (resClass == DXIL::ResourceClass::Invalid)
+    return RP;
+
+  llvm::Type *Ty = CGM.getTypes().ConvertType(resTy);
+  switch (resClass) {
+  case DXIL::ResourceClass::UAV: {
+    DxilResource UAV;
+    // TODO: save globalcoherent to variable in EmitHLSLBuiltinCallExpr.
+    SetUAVSRV(loc, resClass, &UAV, resTy);
+    UAV.SetGlobalSymbol(UndefValue::get(Ty->getPointerTo()));
+    RP = resource_helper::loadFromResourceBase(&UAV);
+  } break;
+  case DXIL::ResourceClass::SRV: {
+    DxilResource SRV;
+    SetUAVSRV(loc, resClass, &SRV, resTy);
+    SRV.SetGlobalSymbol(UndefValue::get(Ty->getPointerTo()));
+    RP = resource_helper::loadFromResourceBase(&SRV);
+  } break;
+  case DXIL::ResourceClass::Sampler: {
+    DxilSampler::SamplerKind kind = KeywordToSamplerKind(RD->getName());
+
+    RP.Class = DXIL::ResourceClass::Sampler;
+    RP.Kind = DXIL::ResourceKind::Sampler;
+    if (kind == DXIL::SamplerKind::Comparison)
+      RP.Kind = DXIL::ResourceKind::SamplerComparison;
+  }
+  default:
+    break;
+  }
+  return RP;
+}
+
 void CGMSHLSLRuntime::ConstructFieldAttributedAnnotation(
     DxilFieldAnnotation &fieldAnnotation, QualType fieldTy,
     bool bDefaultRowMajor) {
@@ -844,7 +904,8 @@ void CGMSHLSLRuntime::ConstructFieldAttributedAnnotation(
     EltTy = hlsl::GetHLSLVecElementType(Ty);
 
   if (IsHLSLResourceType(Ty)) {
-    MDNode *MD = GetOrAddResTypeMD(Ty);
+    // Always create for llvm::Type could be same for different QualType.
+    MDNode *MD = GetOrAddResTypeMD(Ty, /*bCreate*/ true);
     fieldAnnotation.SetResourceAttribute(MD);
   }
 
@@ -1175,7 +1236,7 @@ void CGMSHLSLRuntime::AddHLSLFunctionInfo(Function *F, const FunctionDecl *FD) {
     hlsl::DxilResourceBase::Class resClass = TypeToClass(qTy);
     if (resClass != hlsl::DxilResourceBase::Class::Invalid) {
       if (!resMetadataMap.count(Ty)) {
-        MDNode *Meta = GetOrAddResTypeMD(qTy);
+        MDNode *Meta = GetOrAddResTypeMD(qTy, /**/false);
         DXASSERT(Meta, "else invalid resource type");
         resMetadataMap[Ty] = Meta;
       }
@@ -1626,11 +1687,14 @@ void CGMSHLSLRuntime::AddHLSLFunctionInfo(Function *F, const FunctionDecl *FD) {
   unsigned ArgNo = 0;
   unsigned ParmIdx = 0;
 
+  auto ArgIt = F->arg_begin();
+
   if (const CXXMethodDecl *MethodDecl = dyn_cast<CXXMethodDecl>(FD)) {
     if (MethodDecl->isInstance()) {
       QualType ThisTy = MethodDecl->getThisType(FD->getASTContext());
       DxilParameterAnnotation &paramAnnotation =
           FuncAnnotation->GetParameterAnnotation(ArgNo++);
+      ++ArgIt;
       // Construct annoation for this pointer.
       ConstructFieldAttributedAnnotation(paramAnnotation, ThisTy,
                                          bDefaultRowMajor);
@@ -1643,6 +1707,11 @@ void CGMSHLSLRuntime::AddHLSLFunctionInfo(Function *F, const FunctionDecl *FD) {
   if (F->getReturnType()->isVoidTy() && !retTy->isVoidType()) {
     // SRet.
     pRetTyAnnotation = &FuncAnnotation->GetParameterAnnotation(ArgNo++);
+    // Save resource properties for parameters.
+    DxilResourceProperties RP = BuildResourceProperty(retTy);
+    if (RP.Class != DXIL::ResourceClass::Invalid)
+      valToResPropertiesMap[ArgIt] = RP;
+    ++ArgIt;
   } else {
     pRetTyAnnotation = &FuncAnnotation->GetRetTypeAnnotation();
   }
@@ -1678,13 +1747,18 @@ void CGMSHLSLRuntime::AddHLSLFunctionInfo(Function *F, const FunctionDecl *FD) {
   bool hasOutVertices = false;
   bool hasOutPrimitives = false;
   bool hasInPayload = false;
-  for (; ArgNo < F->arg_size(); ++ArgNo, ++ParmIdx) {
+  for (; ArgNo < F->arg_size(); ++ArgNo, ++ParmIdx, ++ArgIt) {
     DxilParameterAnnotation &paramAnnotation =
         FuncAnnotation->GetParameterAnnotation(ArgNo);
 
     const ParmVarDecl *parmDecl = FD->getParamDecl(ParmIdx);
 
     QualType fieldTy = parmDecl->getType();
+    // Save resource properties for parameters.
+    DxilResourceProperties RP = BuildResourceProperty(fieldTy);
+    if (RP.Class != DXIL::ResourceClass::Invalid)
+      valToResPropertiesMap[ArgIt] = RP;
+
     // if parameter type is a typedef, try to desugar it first.
     if (isa<TypedefType>(fieldTy.getTypePtr()))
       fieldTy = fieldTy.getDesugaredType(FD->getASTContext());
@@ -2321,7 +2395,16 @@ void CGMSHLSLRuntime::AddControlFlowHint(CodeGenFunction &CGF, const Stmt &S,
   }
 }
 
-void CGMSHLSLRuntime::FinishAutoVar(CodeGenFunction &CGF, const VarDecl &D, llvm::Value *V) {
+void CGMSHLSLRuntime::MarkRetTemp(CodeGenFunction &CGF, Value *V,
+                                 QualType QualTy) {
+  // Save resource properties for ret temp.
+  DxilResourceProperties RP = BuildResourceProperty(QualTy);
+  if (RP.Class != DXIL::ResourceClass::Invalid)
+    valToResPropertiesMap[V] = RP;
+}
+
+void CGMSHLSLRuntime::FinishAutoVar(CodeGenFunction &CGF, const VarDecl &D,
+                                    llvm::Value *V) {
   if (D.hasAttr<HLSLPreciseAttr>()) {
     AllocaInst *AI = cast<AllocaInst>(V);
     HLModule::MarkPreciseAttributeWithMetadata(AI);
@@ -2330,6 +2413,10 @@ void CGMSHLSLRuntime::FinishAutoVar(CodeGenFunction &CGF, const VarDecl &D, llvm
   DxilTypeSystem &typeSys = m_pHLModule->GetTypeSystem();
   unsigned arrayEltSize = 0;
   AddTypeAnnotation(D.getType(), typeSys, arrayEltSize);
+  // Save resource properties for local variables.
+  DxilResourceProperties RP = BuildResourceProperty(D.getType());
+  if (RP.Class != DXIL::ResourceClass::Invalid)
+    valToResPropertiesMap[V] = RP;
 }
 
 hlsl::InterpolationMode CGMSHLSLRuntime::GetInterpMode(const Decl *decl,
@@ -2408,6 +2495,13 @@ void CGMSHLSLRuntime::addResource(Decl *D) {
     GetOrCreateCBuffer(BD);
   else if (VarDecl *VD = dyn_cast<VarDecl>(D)) {
     hlsl::DxilResourceBase::Class resClass = TypeToClass(VD->getType());
+    // Save resource properties for global variables.
+    if (resClass != DXIL::ResourceClass::Invalid) {
+      GlobalVariable *GV = cast<GlobalVariable>(CGM.GetAddrOfGlobalVar(VD));
+      DxilResourceProperties RP = BuildResourceProperty(VD->getType());
+      if (RP.Class != DXIL::ResourceClass::Invalid)
+        valToResPropertiesMap[GV] = RP;
+    }
     // skip decl has init which is resource.
     if (VD->hasInit() && resClass != DXIL::ResourceClass::Invalid)
       return;
@@ -2891,7 +2985,6 @@ static void CollectScalarTypes(std::vector<QualType> &ScalarTys, QualType Ty) {
 bool CGMSHLSLRuntime::SetUAVSRV(SourceLocation loc,
                                 hlsl::DxilResourceBase::Class resClass,
                                 DxilResource *hlslRes, QualType QualTy) {
-
   RecordDecl *RD = QualTy->getAs<RecordType>()->getDecl();
 
   hlsl::DxilResource::Kind kind = KeywordToKind(RD->getName());
@@ -3007,7 +3100,9 @@ bool CGMSHLSLRuntime::SetUAVSRV(SourceLocation loc,
     uint32_t strideInBytes = dataLayout.getTypeAllocSize(retTy);
     hlslRes->SetElementStride(strideInBytes);
   }
-
+  if (HasHLSLGloballyCoherent(QualTy)) {
+    hlslRes->SetGloballyCoherent(true);
+  }
   if (resClass == hlsl::DxilResourceBase::Class::SRV) {
     if (hlslRes->IsGloballyCoherent()) {
       DiagnosticsEngine &Diags = CGM.getDiags();
@@ -3109,6 +3204,10 @@ void CGMSHLSLRuntime::AddConstant(VarDecl *constDecl, HLCBuffer &CB) {
   }
   llvm::Constant *constVal = CGM.GetAddrOfGlobalVar(constDecl);
   auto &regBindings = constantRegBindingMap[constVal];
+  // Save resource properties for cbuffer variables.
+  DxilResourceProperties RP = BuildResourceProperty(constDecl->getType());
+  if (RP.Class != DXIL::ResourceClass::Invalid)
+    valToResPropertiesMap[constVal] = RP;
 
   bool isGlobalCB = CB.GetID() == globalCBIndex;
   uint32_t offset = 0;
@@ -3959,7 +4058,91 @@ static Value *CreateHandleFromResPtr(
   return Handle;
 }
 
-static void AddOpcodeParamForIntrinsic(HLModule &HLM, Function *F,
+namespace {
+
+Value *CreateAnnotateHandle(HLModule &HLM, Value *Handle,
+                            DxilResourceProperties &RP, llvm::Type *ResTy,
+                            IRBuilder<> &Builder) {
+  Constant *RPConstant = resource_helper::getAsConstant(
+      RP, HLM.GetOP()->GetResourcePropertiesType(), *HLM.GetShaderModel());
+  return HLM.EmitHLOperationCall(
+      Builder, HLOpcodeGroup::HLAnnotateHandle,
+      (unsigned)HLOpcodeGroup::HLAnnotateHandle, Handle->getType(),
+      {Handle, Builder.getInt8((uint8_t)RP.Class),
+       Builder.getInt8((uint8_t)RP.Kind), RPConstant, UndefValue::get(ResTy)},
+      *HLM.GetModule());
+}
+
+void LowerGetResourceFromHeap(
+    HLModule &HLM, std::vector<std::pair<Function *, unsigned>> &intrinsicMap) {
+  llvm::Module &M = *HLM.GetModule();
+  llvm::Type *HandleTy = HLM.GetOP()->GetHandleType();
+  unsigned GetResFromHeapOp =
+      static_cast<unsigned>(IntrinsicOp::IOP_GetResourceFromHeap);
+  DenseMap<Instruction *, Instruction *> ResourcePtrToHandlePtrMap;
+
+  for (auto it : intrinsicMap) {
+    unsigned opcode = it.second;
+    if (opcode != GetResFromHeapOp)
+      continue;
+    Function *F = it.first;
+    for (auto uit = F->user_begin(); uit != F->user_end();) {
+      CallInst *CI = cast<CallInst>(*(uit++));
+      Instruction *ResPtr = cast<Instruction>(CI->getArgOperand(0));
+      Value *Index = CI->getArgOperand(1);
+      IRBuilder<> Builder(CI);
+      // Make a handle from GetResFromHeap.
+      Value *Handle =
+          HLM.EmitHLOperationCall(Builder, HLOpcodeGroup::HLIntrinsic,
+                                  GetResFromHeapOp, HandleTy, {Index}, M);
+
+      // Find the handle ptr for res ptr.
+      auto it = ResourcePtrToHandlePtrMap.find(ResPtr);
+      Instruction *HandlePtr = nullptr;
+      if (it != ResourcePtrToHandlePtrMap.end()) {
+        HandlePtr = it->second;
+      } else {
+        IRBuilder<> AllocaBuilder(
+            ResPtr->getParent()->getParent()->getEntryBlock().begin());
+        HandlePtr = AllocaBuilder.CreateAlloca(HandleTy);
+        ResourcePtrToHandlePtrMap[ResPtr] = HandlePtr;
+      }
+      // Store handle to handle ptr.
+      Builder.CreateStore(Handle, HandlePtr);
+      CI->eraseFromParent();
+    }
+  }
+
+  // Replace load of Resource ptr into load of handel ptr.
+  for (auto it : ResourcePtrToHandlePtrMap) {
+    Instruction *resPtr = it.first;
+    Instruction *handlePtr = it.second;
+
+    for (auto uit = resPtr->user_begin(); uit != resPtr->user_end();) {
+      User *U = *(uit++);
+      BitCastInst *BCI = cast<BitCastInst>(U);
+      DXASSERT(
+          dxilutil::IsHLSLResourceType(BCI->getType()->getPointerElementType()),
+          "illegal cast of resource ptr");
+      for (auto cuit = BCI->user_begin(); cuit != BCI->user_end();) {
+        LoadInst *LI = cast<LoadInst>(*(cuit++));
+        IRBuilder<> Builder(LI);
+        Value *Handle = Builder.CreateLoad(handlePtr);
+        Value *Res =
+            HLM.EmitHLOperationCall(Builder, HLOpcodeGroup::HLCast,
+                                    (unsigned)HLCastOpcode::HandleToResCast,
+                                    LI->getType(), {Handle}, M);
+        LI->replaceAllUsesWith(Res);
+        LI->eraseFromParent();
+      }
+      BCI->eraseFromParent();
+    }
+    resPtr->eraseFromParent();
+  }
+}
+} // namespace
+
+void CGMSHLSLRuntime::AddOpcodeParamForIntrinsic(HLModule &HLM, Function *F,
                                        unsigned opcode, llvm::Type *HandleTy,
     std::unordered_map<llvm::Type *, MDNode*> &resMetaMap) {
   llvm::Module &M = *HLM.GetModule();
@@ -4061,6 +4244,8 @@ static void AddOpcodeParamForIntrinsic(HLModule &HLM, Function *F,
   if (!lower.empty())
     hlsl::SetHLLowerStrategy(opFunc, lower);
 
+  DxilTypeSystem &typeSys = HLM.GetTypeSystem();
+
   for (auto user = F->user_begin(); user != F->user_end();) {
     // User must be a call.
     CallInst *oldCI = cast<CallInst>(*(user++));
@@ -4118,6 +4303,8 @@ static void AddOpcodeParamForIntrinsic(HLModule &HLM, Function *F,
       if (Ty->isPointerTy()) {
         Ty = Ty->getPointerElementType();
         if (dxilutil::IsHLSLResourceType(Ty)) {
+
+          DxilResourceProperties RP;
           // Use object type directly, not by pointer.
           // This will make sure temp object variable only used by ld/st.
           if (GEPOperator *argGEP = dyn_cast<GEPOperator>(arg)) {
@@ -4128,8 +4315,79 @@ static void AddOpcodeParamForIntrinsic(HLModule &HLM, Function *F,
             Builder.Insert(GEP);
             arg = GEP;
           }
+
+          llvm::Type *ResTy = arg->getType()->getPointerElementType();
+
+          auto RPIt = valToResPropertiesMap.find(arg);
+          if (RPIt != valToResPropertiesMap.end())
+          {
+            RP = RPIt->second;
+          } else {
+            // Must be GEP.
+            GEPOperator *GEP = cast<GEPOperator>(arg);
+            // Find RP from GEP.
+            Value *Ptr = GEP->getPointerOperand();
+            // When Ptr is array of resource, check if it is another GEP.
+            while (dxilutil::IsHLSLResourceType(
+                    dxilutil::GetArrayEltTy(Ptr->getType()))) {
+              if (GEPOperator *ParentGEP = dyn_cast<GEPOperator>(Ptr)) {
+                GEP = ParentGEP;
+                Ptr = GEP->getPointerOperand();
+              } else {
+                break;
+              }
+            }
+
+            RPIt = valToResPropertiesMap.find(Ptr);
+            // When ptr is array of resource, ptr could be in valToResPropertiesMap.
+            if (RPIt != valToResPropertiesMap.end()) {
+              RP = RPIt->second;
+            } else {
+              DxilStructAnnotation *Anno = nullptr;
+
+              for (auto gepIt = gep_type_begin(GEP), E = gep_type_end(GEP);
+                   gepIt != E; ++gepIt) {
+
+                if (StructType *ST = dyn_cast<StructType>(*gepIt)) {
+                  Anno = typeSys.GetStructAnnotation(ST);
+                  DXASSERT(Anno, "missing type annotation");
+
+                  unsigned Index = cast<ConstantInt>(gepIt.getOperand())->getLimitedValue();
+
+                  DxilFieldAnnotation &fieldAnno =
+                      Anno->GetFieldAnnotation(Index);
+                  if (fieldAnno.HasResourceAttribute()) {
+                    MDNode *resAttrib = fieldAnno.GetResourceAttribute();
+                    DxilResourceBase R(DXIL::ResourceClass::Invalid);
+                    HLM.LoadDxilResourceBaseFromMDNode(resAttrib, R);
+                    switch (R.GetClass()) {
+                    case DXIL::ResourceClass::SRV:
+                    case DXIL::ResourceClass::UAV: {
+                      DxilResource Res;
+                      HLM.LoadDxilResourceFromMDNode(resAttrib, Res);
+                      RP = resource_helper::loadFromResourceBase(&Res);
+                    } break;
+                    case DXIL::ResourceClass::Sampler: {
+                      DxilSampler Sampler;
+                      HLM.LoadDxilSamplerFromMDNode(resAttrib, Sampler);
+                      RP = resource_helper::loadFromResourceBase(&Sampler);
+                    } break;
+                    default:
+                      DXASSERT(
+                          0, "invalid resource attribute in filed annotation");
+                      break;
+                    }
+                    break;
+                  }
+                }
+              }
+            }
+          }
+
+          DXASSERT(RP.Class != DXIL::ResourceClass::Invalid, "invalid resource properties");
           Value *Handle = CreateHandleFromResPtr(arg, HLM, HandleTy,
                                                  resMetaMap, Builder);
+          Handle = CreateAnnotateHandle(HLM, Handle, RP, ResTy, Builder);
           opcodeParamList[i] = Handle;
         }
       }
@@ -4155,7 +4413,8 @@ static void AddOpcodeParamForIntrinsic(HLModule &HLM, Function *F,
   F->eraseFromParent();
 }
 
-static void AddOpcodeParamForIntrinsics(HLModule &HLM
+void CGMSHLSLRuntime::AddOpcodeParamForIntrinsics(
+    HLModule &HLM
     , std::vector<std::pair<Function *, unsigned>> &intrinsicMap,
     std::unordered_map<llvm::Type *, MDNode*> &resMetaMap) {
   llvm::Type *HandleTy = HLM.GetOP()->GetHandleType();
@@ -5200,6 +5459,14 @@ void TranslateRayQueryConstructor(llvm::Module &M) {
 }
 
 void CGMSHLSLRuntime::FinishCodeGen() {
+  // Lower getResourceHeap before AddOpcodeParamForIntrinsics to skip automatic
+  // lower for getResourceFromHeap.
+  LowerGetResourceFromHeap(*m_pHLModule, m_IntrinsicMap);
+  // translate opcode into parameter for intrinsic functions
+  // Do this before CloneShaderEntry and TranslateRayQueryConstructor to avoid
+  // update valToResPropertiesMap for cloned inst.
+  AddOpcodeParamForIntrinsics(*m_pHLModule, m_IntrinsicMap, resMetadataMap);
+
   // Library don't have entry.
   if (!m_bIsLib) {
     SetEntryFunction();
@@ -5226,7 +5493,8 @@ void CGMSHLSLRuntime::FinishCodeGen() {
         continue;
 
       // TODO: change flattened function names to dx.entry.<name>:
-      //std::string entryName = (Twine(dxilutil::EntryPrefix) + it.getKey()).str();
+      // std::string entryName = (Twine(dxilutil::EntryPrefix) +
+      // it.getKey()).str();
       CloneShaderEntry(it.second.Func, it.getKey(), *m_pHLModule);
 
       auto AttrIter = HSEntryPatchConstantFuncAttr.find(it.second.Func);
@@ -5281,8 +5549,6 @@ void CGMSHLSLRuntime::FinishCodeGen() {
     ProcessCtorFunctions(TheModule ,"llvm.global_ctors",
                   Entry.Func->getEntryBlock().getFirstInsertionPt());
   }
-  // translate opcode into parameter for intrinsic functions
-  AddOpcodeParamForIntrinsics(*m_pHLModule, m_IntrinsicMap, resMetadataMap);
 
   // Register patch constant functions referenced by exported Hull Shaders
   if (m_bIsLib && !m_ExportMap.empty()) {
@@ -7302,6 +7568,15 @@ void CGMSHLSLRuntime::EmitHLSLFlatConversionAggregateCopy(CodeGenFunction &CGF,
       CGF.Builder.CreateMemCpy(DestPtr, SrcPtr, size, 1);
       return;
     }
+  } else if (dxilutil::IsHLSLResourceDescType(SrcPtrTy) &&
+             dxilutil::IsHLSLResourceType(DestPtrTy)) {
+    // Cast resource desc to resource.
+    Value *CastPtr = CGF.Builder.CreatePointerCast(SrcPtr, DestPtr->getType());
+    // Load resource.
+    Value *V = CGF.Builder.CreateLoad(CastPtr);
+    // Store to resource ptr.
+    CGF.Builder.CreateStore(V, DestPtr);
+    return;
   } else if (dxilutil::IsHLSLObjectType(dxilutil::GetArrayEltTy(SrcPtrTy)) &&
              dxilutil::IsHLSLObjectType(dxilutil::GetArrayEltTy(DestPtrTy))) {
     unsigned sizeSrc = TheModule.getDataLayout().getTypeAllocSize(SrcPtrTy);

+ 2 - 0
tools/clang/lib/CodeGen/CGHLSLRuntime.h

@@ -75,6 +75,8 @@ public:
       const std::function<void(const VarDecl *, llvm::Value *)> &TmpArgMap) = 0;
   virtual void EmitHLSLOutParamConversionCopyBack(
       CodeGenFunction &CGF, llvm::SmallVector<LValue, 8> &castArgList) = 0;
+  virtual void MarkRetTemp(CodeGenFunction &CGF, llvm::Value *V,
+                          clang::QualType QaulTy) = 0;
   virtual llvm::Value *EmitHLSLMatrixOperationCall(CodeGenFunction &CGF, const clang::Expr *E, llvm::Type *RetType,
       llvm::ArrayRef<llvm::Value*> paramList) = 0;
   virtual void EmitHLSLDiscard(CodeGenFunction &CGF) = 0;

+ 39 - 13
tools/clang/lib/Sema/SemaHLSL.cpp

@@ -205,6 +205,8 @@ enum ArBasicKind {
   // RayQuery
   AR_OBJECT_RAY_QUERY,
 
+  // Resource
+  AR_OBJECT_RESOURCE,
   AR_BASIC_MAXIMUM_COUNT
 };
 
@@ -488,7 +490,7 @@ const UINT g_uBasicKindProps[] =
   0,      //AR_OBJECT_RAYTRACING_PIPELINE_CONFIG1,
 
   0,      //AR_OBJECT_RAY_QUERY,
-
+  0,      //AR_OBJECT_RESOURCE,
   // AR_BASIC_MAXIMUM_COUNT
 };
 
@@ -1117,6 +1119,9 @@ static const ArBasicKind g_Texture2DArrayCT[] =
   AR_BASIC_UNKNOWN
 };
 
+static const ArBasicKind g_ResourceCT[] = {AR_OBJECT_RESOURCE,
+                                           AR_BASIC_UNKNOWN};
+
 static const ArBasicKind g_RayDescCT[] =
 {
   AR_OBJECT_RAY_DESC,
@@ -1230,6 +1235,7 @@ const ArBasicKind* g_LegalIntrinsicCompTypes[] =
   g_UDTCT,              // LICOMPTYPE_USER_DEFINED_TYPE
   g_Texture2DCT,        // LICOMPTYPE_TEXTURE2D
   g_Texture2DArrayCT,   // LICOMPTYPE_TEXTURE2DARRAY
+  g_ResourceCT,         // LICOMPTYPE_RESOURCE
 };
 static_assert(ARRAYSIZE(g_LegalIntrinsicCompTypes) == LICOMPTYPE_COUNT,
   "Intrinsic comp type table must be updated when new enumerants are added.");
@@ -1320,7 +1326,8 @@ const ArBasicKind g_ArBasicKindsAsTypes[] =
   AR_OBJECT_PROCEDURAL_PRIMITIVE_HIT_GROUP,
   AR_OBJECT_RAYTRACING_PIPELINE_CONFIG1,
 
-  AR_OBJECT_RAY_QUERY
+  AR_OBJECT_RAY_QUERY,
+  AR_OBJECT_RESOURCE,
 };
 
 // Count of template arguments for basic kind of objects that look like templates (one or more type arguments).
@@ -1406,6 +1413,7 @@ const uint8_t g_ArBasicKindsTemplateCount[] =
   0, // AR_OBJECT_RAYTRACING_PIPELINE_CONFIG1,
 
   1, // AR_OBJECT_RAY_QUERY,
+  0, // AR_OBJECT_RESOURCE,
 };
 
 C_ASSERT(_countof(g_ArBasicKindsAsTypes) == _countof(g_ArBasicKindsTemplateCount));
@@ -1501,6 +1509,7 @@ const SubscriptOperatorRecord g_ArBasicKindsSubscripts[] =
   { 0, MipsFalse, SampleFalse },  // AR_OBJECT_RAYTRACING_PIPELINE_CONFIG1,
 
   { 0, MipsFalse, SampleFalse },  // AR_OBJECT_RAY_QUERY,
+  { 0, MipsFalse, SampleFalse },  // AR_OBJECT_RESOURCE,
 };
 
 C_ASSERT(_countof(g_ArBasicKindsAsTypes) == _countof(g_ArBasicKindsSubscripts));
@@ -1619,7 +1628,8 @@ const char* g_ArBasicTypeNames[] =
   "ProceduralPrimitiveHitGroup",
   "RaytracingPipelineConfig1",
 
-  "RayQuery"
+  "RayQuery",
+  "Resource",
 };
 
 C_ASSERT(_countof(g_ArBasicTypeNames) == AR_BASIC_MAXIMUM_COUNT);
@@ -3321,6 +3331,8 @@ private:
         }
       } else if (kind == AR_OBJECT_RAY_QUERY) {
         recordDecl = DeclareRayQueryType(*m_context);
+      } else if (kind == AR_OBJECT_RESOURCE) {
+        recordDecl = DeclareResourceType(*m_context);
       }
       else if (kind == AR_OBJECT_FEEDBACKTEXTURE2D) {
         recordDecl = DeclareUIntTemplatedTypeWithHandle(*m_context, "FeedbackTexture2D", "kind");
@@ -3987,6 +3999,8 @@ public:
     case AR_OBJECT_SAMPLER:
     case AR_OBJECT_SAMPLERCOMPARISON:
 
+    case AR_OBJECT_RESOURCE:
+
     case AR_OBJECT_BUFFER:
 
     case AR_OBJECT_POINTSTREAM:
@@ -8377,6 +8391,14 @@ bool HLSLExternalSource::CanConvert(
     goto lSuccess;
   }
 
+  // Cast from Resource to Object types.
+  if (SourceInfo.EltKind == AR_OBJECT_RESOURCE) {
+    if (TargetInfo.ShapeKind == AR_TOBJ_OBJECT) {
+      Second = ICK_Flat_Conversion;
+      goto lSuccess;
+    }
+  }
+
   // Convert scalar/vector/matrix dimensions
   if (!ConvertDimensions(TargetInfo, SourceInfo, Second, Remarks))
     return false;
@@ -12142,20 +12164,18 @@ static QualType getUnderlyingType(QualType Type)
 /// <param name="ppMatrixOrientation">Set pointer to column_major/row_major AttributedType if supplied.</param>
 /// <param name="ppNorm">Set pointer to snorm/unorm AttributedType if supplied.</param>
 void hlsl::GetHLSLAttributedTypes(
-  _In_ clang::Sema* self,
-  clang::QualType type, 
-  _Inout_opt_ const clang::AttributedType** ppMatrixOrientation, 
-  _Inout_opt_ const clang::AttributedType** ppNorm)
-{
-  if (ppMatrixOrientation)
-    *ppMatrixOrientation = nullptr;
-  if (ppNorm)
-    *ppNorm = nullptr;
+    _In_ clang::Sema *self, clang::QualType type,
+    _Inout_opt_ const clang::AttributedType **ppMatrixOrientation,
+    _Inout_opt_ const clang::AttributedType **ppNorm,
+    _Inout_opt_ const clang::AttributedType **ppGLC) {
+  AssignOpt<const clang::AttributedType *>(nullptr, ppMatrixOrientation);
+  AssignOpt<const clang::AttributedType *>(nullptr, ppNorm);
+  AssignOpt<const clang::AttributedType *>(nullptr, ppGLC);
 
   // Note: we clear output pointers once set so we can stop searching
   QualType Desugared = getUnderlyingType(type);
   const AttributedType *AT = dyn_cast<AttributedType>(Desugared);
-  while (AT && (ppMatrixOrientation || ppNorm)) {
+  while (AT && (ppMatrixOrientation || ppNorm || ppGLC)) {
     AttributedType::Kind Kind = AT->getAttrKind();
 
     if (Kind == AttributedType::attr_hlsl_row_major ||
@@ -12176,6 +12196,12 @@ void hlsl::GetHLSLAttributedTypes(
         ppNorm = nullptr;
       }
     }
+    else if (Kind == AttributedType::attr_hlsl_globallycoherent) {
+      if (ppGLC) {
+        *ppGLC = AT;
+        ppGLC = nullptr;
+      }
+    }
 
     Desugared = getUnderlyingType(AT->getEquivalentType());
     AT = dyn_cast<AttributedType>(Desugared);

+ 20 - 1
tools/clang/lib/Sema/SemaType.cpp

@@ -4514,6 +4514,8 @@ static AttributeList::Kind getAttrListKind(AttributedType::Kind kind) {
     return AttributeList::AT_HLSLRowMajor;
   case AttributedType::attr_hlsl_column_major:
     return AttributeList::AT_HLSLColumnMajor;
+  case AttributedType::attr_hlsl_globallycoherent:
+    return AttributeList::AT_HLSLGloballyCoherent;
   // HLSL Change Ends
   }
   llvm_unreachable("unexpected attribute kind!");
@@ -5756,6 +5758,7 @@ static bool isHLSLTypeAttr(AttributeList::Kind Kind) {
   case AttributeList::AT_HLSLColumnMajor:
   case AttributeList::AT_HLSLSnorm:
   case AttributeList::AT_HLSLUnorm:
+  case AttributeList::AT_HLSLGloballyCoherent:
     return true;
   default:
     // Only meant to catch attr handled by handleHLSLTypeAttr, ignore the rest
@@ -5782,11 +5785,17 @@ static bool handleHLSLTypeAttr(TypeProcessingState &State,
               !hlsl::GetOriginalElementType(&S, Type)->isFloatingType()) {
     S.Diag(Attr.getLoc(), diag::err_hlsl_norm_float_only) << Attr.getRange();
     return true;
+  } else if (Kind == AttributeList::AT_HLSLGloballyCoherent &&
+             !hlsl::IsObjectType(&S, Type)) {
+    S.Diag(Attr.getLoc(), diag::err_hlsl_varmodifierna) <<
+        Attr.getName() << "non-UAV type";
+    return true;
   }
 
   const AttributedType *pMatrixOrientation = nullptr;
   const AttributedType *pNorm = nullptr;
-  hlsl::GetHLSLAttributedTypes(&S, Type, &pMatrixOrientation, &pNorm);
+  const AttributedType *pGLC = nullptr;
+  hlsl::GetHLSLAttributedTypes(&S, Type, &pMatrixOrientation, &pNorm, &pGLC);
 
   if (pMatrixOrientation &&
     (Kind == AttributeList::AT_HLSLColumnMajor ||
@@ -5820,6 +5829,14 @@ static bool handleHLSLTypeAttr(TypeProcessingState &State,
     return true;
   }
 
+  if (pGLC && Kind == AttributeList::AT_HLSLGloballyCoherent) {
+    AttributedType::Kind CurAttrKind = pGLC->getAttrKind();
+    if (Kind == getAttrListKind(CurAttrKind)) {
+      S.Diag(Attr.getLoc(), diag::warn_duplicate_attribute_exact)
+          << Attr.getName() << Attr.getRange();
+    }
+  }
+
   AttributedType::Kind TAK;
   switch (Kind) {
   default: llvm_unreachable("Unknown attribute kind");
@@ -5827,6 +5844,8 @@ static bool handleHLSLTypeAttr(TypeProcessingState &State,
   case AttributeList::AT_HLSLColumnMajor: TAK = AttributedType::attr_hlsl_column_major; break;
   case AttributeList::AT_HLSLUnorm:       TAK = AttributedType::attr_hlsl_unorm; break;
   case AttributeList::AT_HLSLSnorm:       TAK = AttributedType::attr_hlsl_snorm; break;
+  case AttributeList::AT_HLSLGloballyCoherent:
+    TAK = AttributedType::attr_hlsl_globallycoherent; break;
   }
 
   Type = S.Context.getAttributedType(TAK, Type, Type);

Fichier diff supprimé car celui-ci est trop grand
+ 141 - 135
tools/clang/lib/Sema/gen_intrin_main_tables_15.h


+ 1 - 1
tools/clang/test/HLSLFileCheck/dxil/debug/value_cache/load.hlsl

@@ -1,4 +1,4 @@
-// RUN: %dxc -E main -T ps_6_6 %s -Od | FileCheck %s
+// RUN: %dxc -E main -T ps_6_0 %s -Od | FileCheck %s
 
 Texture2D tex0 : register(t0);
 Texture2D tex1 : register(t42);

+ 1 - 1
tools/clang/test/HLSLFileCheck/dxil/debug/value_cache/resource_array.hlsl

@@ -1,4 +1,4 @@
-// RUN: %dxc -E main -T ps_6_6 %s -Od | FileCheck %s
+// RUN: %dxc -E main -T ps_6_0 %s -Od | FileCheck %s
 
 Texture2D tex0[42] : register(t0);
 Texture2D tex1 : register(t42);

+ 1 - 2
tools/clang/test/HLSLFileCheck/dxil/debug/value_cache/right_branch.hlsl

@@ -1,4 +1,4 @@
-// RUN: %dxc -E main -T ps_6_6 %s -Od | FileCheck %s
+// RUN: %dxc -E main -T ps_6_0 %s -Od | FileCheck %s
 
 // Make sure DxilValueCache actually predicts the correct branch
 
@@ -19,7 +19,6 @@ float4 main() : SV_Target {
   if (w >= 0) {
     tex = tex1;
   }
-
   // CHECK: @dx.op.textureLoad.f32(i32 66, %dx.types.Handle %[[handle]]
   return tex.Load(0) + float4(x,y,z,w);
 }

+ 0 - 9
tools/clang/test/HLSLFileCheck/hlsl/intrinsics/basic/abs1.hlsl

@@ -1,9 +0,0 @@
-// RUN: %dxc -E main -T ps_6_0 -fcgl %s | FileCheck %s
-
-// CHECK: main
-// After lowering, these would turn into multiple abs calls rather than a 4 x float
-// CHECK: call <4 x float> @"dx.hl.op..<4 x float> (i32, <4 x float>)"(i32 95,
-
-float4 main(float4 a : A) : SV_TARGET {
-  return abs(a*a.yxxx);
-}

+ 9 - 0
tools/clang/test/HLSLFileCheck/hlsl/intrinsics/createHandleFromHeap/createFromHeap.hlsl

@@ -0,0 +1,9 @@
+// RUN: %dxc -T ps_6_6 %s | %FileCheck %s
+// CHECK:call %dx.types.Handle @dx.op.createHandleFromHeap(i32 216
+// CHECK:call %dx.types.Handle @dx.op.annotateHandle(i32 217, %dx.types.Handle %{{.*}}, i8 0, i8 10, %dx.types.ResourceProperties { i32 41, i32 0 })
+
+uint ID;
+float main(uint i:I): SV_Target {
+  Buffer<float> buf = GetResourceFromHeap(ID);
+  return buf[i];
+}

+ 24 - 0
tools/clang/test/HLSLFileCheck/hlsl/intrinsics/createHandleFromHeap/createFromHeap2.hlsl

@@ -0,0 +1,24 @@
+// RUN: %dxc -T ps_6_6 %s | %FileCheck %s
+
+// Make sure snorm/unorm and globallycoherent works.
+// CHECK:call %dx.types.Handle @dx.op.createHandleFromHeap(i32 216
+// CHECK:call %dx.types.Handle @dx.op.createHandleFromHeap(i32 216
+// CHECK:call %dx.types.Handle @dx.op.createHandleFromHeap(i32 216
+// CHECK:call %dx.types.Handle @dx.op.annotateHandle(i32 217, %dx.types.Handle %{{.*}}, i8 1, i8 10, %dx.types.ResourceProperties { i32 46, i32 0 })
+// CHECK:call %dx.types.Handle @dx.op.annotateHandle(i32 217, %dx.types.Handle %{{.*}}, i8 1, i8 10, %dx.types.ResourceProperties { i32 45, i32 2 })
+// CHECK:call %dx.types.Handle @dx.op.annotateHandle(i32 217, %dx.types.Handle %{{.*}}, i8 1, i8 10, %dx.types.ResourceProperties { i32 45, i32 2 })
+
+
+struct S {
+RWBuffer<unorm float> buf;
+globallycoherent RWBuffer<snorm float> buf1[2];
+};
+
+uint ID;
+float main(uint i:I): SV_Target {
+  S s;
+  s.buf = GetResourceFromHeap(ID);
+  s.buf1[0] = GetResourceFromHeap(ID+1);
+  s.buf1[1] = GetResourceFromHeap(ID+2);
+  return s.buf[i] + s.buf1[0][i] + s.buf1[1][i];
+}

+ 5 - 1
tools/clang/tools/dxcompiler/dxcdisassembler.cpp

@@ -366,6 +366,7 @@ void PrintResourceFormat(DxilResourceBase &res, unsigned alignment,
       OS << right_justify("byte", alignment);
       break;
     case DxilResource::Kind::StructuredBuffer:
+    case DxilResource::Kind::StructuredBufferWithCounter:
       OS << right_justify("struct", alignment);
       break;
     default:
@@ -393,6 +394,7 @@ void PrintResourceDim(DxilResourceBase &res, unsigned alignment,
     switch (res.GetKind()) {
     case DxilResource::Kind::RawBuffer:
     case DxilResource::Kind::StructuredBuffer:
+    case DxilResource::Kind::StructuredBufferWithCounter:
       if (res.GetClass() == DxilResourceBase::Class::SRV)
         OS << right_justify("r/o", alignment);
       else {
@@ -1275,7 +1277,9 @@ static const char *OpCodeSignatures[] = {
   "(rayQueryHandle,component)",  // RayQuery_CommittedObjectRayDirection
   "()",  // GeometryIndex
   "(rayQueryHandle)",  // RayQuery_CandidateInstanceContributionToHitGroupIndex
-  "(rayQueryHandle)"  // RayQuery_CommittedInstanceContributionToHitGroupIndex
+  "(rayQueryHandle)",  // RayQuery_CommittedInstanceContributionToHitGroupIndex
+  "(index)",  // CreateHandleFromHeap
+  "(res,resourceClass,resourceKind,props)"  // AnnotateHandle
 };
 // OPCODE-SIGS:END
 

+ 2 - 0
utils/hct/gen_intrin_main.txt

@@ -324,6 +324,8 @@ void [[]] DispatchMesh(in uint threadGroupCountX, in uint threadGroupCountY, in
 // HL Op for allocating ray query object that default constructor uses
 uint [[hidden]] AllocateRayQuery(in uint flags);
 
+resource [[rn]] GetResourceFromHeap(in uint index);
+
 } namespace
 
 namespace StreamMethods {

+ 21 - 0
utils/hct/hctdb.py

@@ -386,6 +386,9 @@ class db_dxil(object):
             self.name_idx[i].category = "Library create handle from resource struct (like HL intrinsic)"
             self.name_idx[i].shader_model = 6,3
             self.name_idx[i].shader_model_translated = 6,0
+        for i in "CreateHandleFromHeap,AnnotateHandle".split(","):
+            self.name_idx[i].category = "Get handle from heap"
+            self.name_idx[i].shader_model = 6,6
         for i in "Dot4AddU8Packed,Dot4AddI8Packed,Dot2AddHalf".split(","):
             self.name_idx[i].category = "Dot product with accumulate"
             self.name_idx[i].shader_model = 6,4
@@ -1727,6 +1730,23 @@ class db_dxil(object):
         self.set_op_count_for_version(1, 5, next_op_idx)
         assert next_op_idx == 216, "216 is expected next operation index but encountered %d and thus opcodes are broken" % next_op_idx
 
+        self.add_dxil_op("CreateHandleFromHeap", next_op_idx, "CreateHandleFromHeap", "create resource handle from heap", "v", "ro", [
+            db_dxil_param(0, "res", "", "result"),
+            db_dxil_param(2, "i32", "index", "heap index")])
+        next_op_idx += 1
+
+        self.add_dxil_op("AnnotateHandle", next_op_idx, "AnnotateHandle", "annotate handle with resource properties", "v", "rn", [
+            db_dxil_param(0, "res", "", "annotated handle"),
+            db_dxil_param(2, "res", "res", "input handle"),
+            db_dxil_param(3, "i8", "resourceClass", "the class of resource to create (SRV, UAV, CBuffer, Sampler)", is_const=True), # maps to DxilResourceBase::Class
+            db_dxil_param(4, "i8", "resourceKind", "the kind of resource to create (Texture1D/2D/..., Buffer...)", is_const=True), # maps to DxilResourceBase::Kind
+            db_dxil_param(5, "resproperty", "props", "details like component type, strutrure stride...")])
+        next_op_idx += 1
+
+        # End of DXIL 1.6 opcodes.
+        self.set_op_count_for_version(1, 6, next_op_idx)
+        assert next_op_idx == 218, "next operation index is %d rather than 165 and thus opcodes are broken" % next_op_idx
+
         # Set interesting properties.
         self.build_indices()
         for i in "CalculateLOD,DerivCoarseX,DerivCoarseY,DerivFineX,DerivFineY,Sample,SampleBias,SampleCmp,TextureGather,TextureGatherCmp".split(","):
@@ -2662,6 +2682,7 @@ class db_hlsl(object):
             "sampler_cube": "LICOMPTYPE_SAMPLERCUBE",
             "sampler_cmp": "LICOMPTYPE_SAMPLERCMP",
             "sampler": "LICOMPTYPE_SAMPLER",
+            "resource": "LICOMPTYPE_RESOURCE",
             "ray_desc" : "LICOMPTYPE_RAYDESC",
             "acceleration_struct" : "LICOMPTYPE_ACCELERATION_STRUCT",
             "udt" : "LICOMPTYPE_USER_DEFINED_TYPE",

+ 1 - 0
utils/hct/hctdb_instrhelp.py

@@ -410,6 +410,7 @@ class db_oload_gen:
             "SamplePos": "A(pPos);",
             "udt": "A(udt);",
             "obj": "A(obj);",
+            "resproperty": "A(resProperty);",
         }
         last_category = None
         for i in self.instrs:

Certains fichiers n'ont pas été affichés car il y a eu trop de fichiers modifiés dans ce diff