Procházet zdrojové kódy

Mutate resource to handle for shader model 6.6+. (#3374)

* Mutate resource to handle for sm_6_6+.

* Use bitcast to save global symbol and HLSL type for DxilResourceBase.
Xiang Li před 4 roky
rodič
revize
797d4b8adc

+ 4 - 0
include/dxc/DXIL/DxilResourceBase.h

@@ -18,6 +18,7 @@
 namespace llvm {
 class Value;
 class Constant;
+class Type;
 }
 
 
@@ -41,6 +42,7 @@ public:
   unsigned GetUpperBound() const;
   unsigned GetRangeSize() const;
   llvm::Constant *GetGlobalSymbol() const;
+  llvm::Type *GetHLSLType() const;
   const std::string &GetGlobalName() const;
   llvm::Value *GetHandle() const;
   bool IsAllocated() const;
@@ -53,6 +55,7 @@ public:
   void SetGlobalSymbol(llvm::Constant *pGV);
   void SetGlobalName(const std::string &Name);
   void SetHandle(llvm::Value *pHandle);
+  void SetHLSLType(llvm::Type *Ty);
 
   // TODO: check whether we can make this a protected method.
   void SetID(unsigned ID);
@@ -76,6 +79,7 @@ private:
   llvm::Constant *m_pSymbol;      // Global variable.
   std::string m_Name;             // Unmangled name of the global variable.
   llvm::Value *m_pHandle;         // Cached resource handle for SM5.0- (and maybe SM5.1).
+  llvm::Type *m_pHLSLTy;           // The original hlsl type for reflection.
 };
 
 const char *GetResourceKindName(DXIL::ResourceKind K);

+ 3 - 0
include/dxc/HLSL/DxilGenerationPass.h

@@ -131,4 +131,7 @@ void initializeDxilNoOptLegalizePass(llvm::PassRegistry&);
 ModulePass *createDxilNoOptSimplifyInstructionsPass();
 void initializeDxilNoOptSimplifyInstructionsPass(llvm::PassRegistry&);
 
+ModulePass *createDxilMutateResourceToHandlePass();
+void initializeDxilMutateResourceToHandlePass(llvm::PassRegistry&);
+
 }

+ 25 - 2
lib/DXIL/DxilMetadataHelper.cpp

@@ -27,6 +27,7 @@
 #include "llvm/IR/LLVMContext.h"
 #include "llvm/IR/Metadata.h"
 #include "llvm/IR/Module.h"
+#include "llvm/IR/IRBuilder.h"
 #include "llvm/Support/raw_ostream.h"
 #include "llvm/ADT/DenseSet.h"
 #include <array>
@@ -594,7 +595,16 @@ void DxilMDHelper::GetDxilResources(const MDOperand &MDO, const MDTuple *&pSRVs,
 
 void DxilMDHelper::EmitDxilResourceBase(const DxilResourceBase &R, Metadata *ppMDVals[]) {
   ppMDVals[kDxilResourceBaseID        ] = Uint32ToConstMD(R.GetID());
-  ppMDVals[kDxilResourceBaseVariable  ] = ValueAsMetadata::get(R.GetGlobalSymbol());
+  Constant *GlobalSymbol = R.GetGlobalSymbol();
+  // For sm66+, global symbol will be mutated into handle type.
+  // Save hlsl type by generate bitcast on global symbol.
+  if (m_pSM->IsSM66Plus()) {
+    Type *HLSLTy = R.GetHLSLType();
+    if (HLSLTy && HLSLTy != GlobalSymbol->getType())
+      GlobalSymbol = cast<Constant>(
+          ConstantExpr::getCast(Instruction::BitCast, GlobalSymbol, HLSLTy));
+  }
+  ppMDVals[kDxilResourceBaseVariable  ] = ValueAsMetadata::get(GlobalSymbol);
   ppMDVals[kDxilResourceBaseName      ] = MDString::get(m_Ctx, R.GetGlobalName());
   ppMDVals[kDxilResourceBaseSpaceID   ] = Uint32ToConstMD(R.GetSpaceID());
   ppMDVals[kDxilResourceBaseLowerBound] = Uint32ToConstMD(R.GetLowerBound());
@@ -608,7 +618,20 @@ void DxilMDHelper::LoadDxilResourceBase(const MDOperand &MDO, DxilResourceBase &
   IFTBOOL(pTupleMD->getNumOperands() >= kDxilResourceBaseNumFields, DXC_E_INCORRECT_DXIL_METADATA);
 
   R.SetID(ConstMDToUint32(pTupleMD->getOperand(kDxilResourceBaseID)));
-  R.SetGlobalSymbol(dyn_cast<Constant>(ValueMDToValue(pTupleMD->getOperand(kDxilResourceBaseVariable))));
+  Constant *GlobalSymbol = dyn_cast<Constant>(ValueMDToValue(pTupleMD->getOperand(kDxilResourceBaseVariable)));
+  // For sm66+, global symbol will be mutated into handle type.
+  // Read hlsl type and global symbol from bitcast.
+  if (m_pSM->IsSM66Plus()) {
+    // Before mutate, there's no bitcast. After GlobalSymbol changed into undef,
+    // there's no bitcast too. Bitcast will only exist when global symbol is
+    // mutated into handle and not changed into undef for lib linking.
+    if (BitCastOperator *BCO = dyn_cast<BitCastOperator>(GlobalSymbol)) {
+      GlobalSymbol = cast<Constant>(BCO->getOperand(0));
+      R.SetHLSLType(BCO->getType());
+    }
+  }
+  R.SetGlobalSymbol(GlobalSymbol);
+
   R.SetGlobalName(StringMDToString(pTupleMD->getOperand(kDxilResourceBaseName)));
   R.SetSpaceID(ConstMDToUint32(pTupleMD->getOperand(kDxilResourceBaseSpaceID)));
   R.SetLowerBound(ConstMDToUint32(pTupleMD->getOperand(kDxilResourceBaseLowerBound)));

+ 1 - 1
lib/DXIL/DxilResource.cpp

@@ -49,7 +49,7 @@ void DxilResource::SetCompType(const CompType CT) {
 }
 
 Type *DxilResource::GetRetType() const {
-  Type *Ty = GetGlobalSymbol()->getType()->getPointerElementType();
+  Type *Ty = GetHLSLType()->getPointerElementType();
   // For resource array, use element type.
   while (Ty->isArrayTy())
     Ty = Ty->getArrayElementType();

+ 11 - 2
lib/DXIL/DxilResourceBase.cpp

@@ -9,6 +9,7 @@
 
 #include "dxc/DXIL/DxilResourceBase.h"
 #include "dxc/Support/Global.h"
+#include "llvm/IR/Constant.h"
 
 
 namespace hlsl {
@@ -26,7 +27,8 @@ DxilResourceBase::DxilResourceBase(Class C)
 , m_LowerBound(0)
 , m_RangeSize(0) 
 , m_pSymbol(nullptr) 
-, m_pHandle(nullptr) {
+, m_pHandle(nullptr)
+, m_pHLSLTy(nullptr) {
 }
 
 DxilResourceBase::Class DxilResourceBase::GetClass() const { return m_Class; }
@@ -43,7 +45,13 @@ unsigned DxilResourceBase::GetUpperBound() const  { return m_RangeSize != UINT_M
 unsigned DxilResourceBase::GetRangeSize() const   { return m_RangeSize; }
 llvm::Constant *DxilResourceBase::GetGlobalSymbol() const { return m_pSymbol; }
 const std::string &DxilResourceBase::GetGlobalName() const      { return m_Name; }
-llvm::Value *DxilResourceBase::GetHandle() const  { return m_pHandle; }
+llvm::Value *DxilResourceBase::GetHandle() const { return m_pHandle; }
+// If m_pHLSLTy is nullptr, HLSL type is the type of m_pSymbol.
+// In sm6.6, type of m_pSymbol will be mutated to handleTy, m_pHLSLTy will save
+// the original HLSL type.
+llvm::Type *DxilResourceBase::GetHLSLType() const {
+  return m_pHLSLTy == nullptr ? m_pSymbol->getType() : m_pHLSLTy;
+}
 bool DxilResourceBase::IsAllocated() const        { return m_LowerBound != UINT_MAX; }
 bool DxilResourceBase::IsUnbounded() const        { return m_RangeSize == UINT_MAX; }
 
@@ -55,6 +63,7 @@ void DxilResourceBase::SetRangeSize(unsigned RangeSize)           { m_RangeSize
 void DxilResourceBase::SetGlobalSymbol(llvm::Constant *pGV)       { m_pSymbol = pGV; }
 void DxilResourceBase::SetGlobalName(const std::string &Name)     { m_Name = Name; }
 void DxilResourceBase::SetHandle(llvm::Value *pHandle)            { m_pHandle = pHandle; }
+void DxilResourceBase::SetHLSLType(llvm::Type *pTy)               { m_pHLSLTy = pTy; }
 
 static const char *s_ResourceClassNames[] = {
     "texture", "UAV", "cbuffer", "sampler"

+ 1 - 0
lib/HLSL/DxcOptimizer.cpp

@@ -109,6 +109,7 @@ HRESULT SetupRegistryPassForHLSL() {
     initializeDxilLoopDeletionPass(Registry);
     initializeDxilLoopUnrollPass(Registry);
     initializeDxilLowerCreateHandleForLibPass(Registry);
+    initializeDxilMutateResourceToHandlePass(Registry);
     initializeDxilNoOptLegalizePass(Registry);
     initializeDxilNoOptSimplifyInstructionsPass(Registry);
     initializeDxilPrecisePropagatePassPass(Registry);

+ 2 - 1
lib/HLSL/DxilCondenseResources.cpp

@@ -1893,7 +1893,7 @@ StructType *UpdateStructTypeForLegacyLayout(StructType *ST,
 void UpdateStructTypeForLegacyLayout(DxilResourceBase &Res,
                                      DxilTypeSystem &TypeSys, Module &M) {
   Constant *Symbol = Res.GetGlobalSymbol();
-  Type *ElemTy = Symbol->getType()->getPointerElementType();
+  Type *ElemTy = Res.GetHLSLType()->getPointerElementType();
   // Support Array of ConstantBuffer/StructuredBuffer.
   llvm::SmallVector<unsigned, 4> arrayDims;
   ElemTy = dxilutil::StripArrayTypes(ElemTy, &arrayDims);
@@ -2307,6 +2307,7 @@ void InitTBuffer(const DxilCBuffer *pSource, DxilResource *pDest) {
   pDest->SetGlobalSymbol(pSource->GetGlobalSymbol());
   pDest->SetGlobalName(pSource->GetGlobalName());
   pDest->SetHandle(pSource->GetHandle());
+  pDest->SetHLSLType(pSource->GetHLSLType());
 }
 
 void PatchTBufferLoad(CallInst *handle, DxilModule &DM,

+ 5 - 6
lib/HLSL/DxilContainerReflection.cpp

@@ -1228,7 +1228,7 @@ void CShaderReflectionConstantBuffer::Initialize(
   // For ConstantBuffer<> buf[2], the array size is in Resource binding count
   // part.
   Type *Ty = dxilutil::StripArrayTypes(
-    CB.GetGlobalSymbol()->getType()->getPointerElementType());
+    CB.GetHLSLType()->getPointerElementType());
 
   DxilTypeSystem &typeSys = M.GetTypeSystem();
   StructType *ST = cast<StructType>(Ty);
@@ -1265,8 +1265,7 @@ void CShaderReflectionConstantBuffer::Initialize(
       DXASSERT(pVarType->m_Desc.Elements == 0,
                "otherwise, assumption is wrong");
       pVarType->m_Desc.Elements = 1;
-    } else if (CB.GetGlobalSymbol()
-                   ->getType()
+    } else if (CB.GetHLSLType()
                    ->getPointerElementType()
                    ->isArrayTy() &&
                CB.GetRangeSize() == 1) {
@@ -1315,7 +1314,7 @@ static unsigned CalcTypeSize(Type *Ty, unsigned &alignment) {
 
 static unsigned CalcResTypeSize(DxilModule &M, DxilResource &R) {
   UNREFERENCED_PARAMETER(M);
-  Type *Ty = R.GetGlobalSymbol()->getType()->getPointerElementType();
+  Type *Ty = R.GetHLSLType()->getPointerElementType();
   if (R.IsStructuredBuffer()) {
     Ty = dxilutil::StripArrayTypes(Ty);
   }
@@ -1351,7 +1350,7 @@ void CShaderReflectionConstantBuffer::InitializeStructuredBuffer(
   // Create reflection type, if we have the necessary annotation info
 
   // Extract the `struct` that wraps element type of the buffer resource
-  Type *Ty = R.GetGlobalSymbol()->getType()->getPointerElementType();
+  Type *Ty = R.GetHLSLType()->getPointerElementType();
   SmallVector<unsigned, 4> arrayDims;
   Ty = dxilutil::StripArrayTypes(Ty, &arrayDims);
   for (unsigned i = 0; i < arrayDims.size(); ++i) {
@@ -1396,7 +1395,7 @@ void CShaderReflectionConstantBuffer::InitializeTBuffer(
   m_Desc.Type = D3D11_CT_TBUFFER;
   m_Desc.uFlags = 0;
 
-  Type *Ty = R.GetGlobalSymbol()->getType()->getPointerElementType();
+  Type *Ty = R.GetHLSLType()->getPointerElementType();
 
   DxilTypeSystem &typeSys = M.GetTypeSystem();
   StructType *ST = cast<StructType>(Ty);

+ 1 - 0
lib/HLSL/DxilGenerationPass.cpp

@@ -76,6 +76,7 @@ void InitResourceBase(const DxilResourceBase *pSource,
   pDest->SetGlobalSymbol(pSource->GetGlobalSymbol());
   pDest->SetGlobalName(pSource->GetGlobalName());
   pDest->SetHandle(pSource->GetHandle());
+  pDest->SetHLSLType(pSource->GetHLSLType());
 
   if (GlobalVariable *GV = dyn_cast<GlobalVariable>(pSource->GetGlobalSymbol()))
     SimplifyGlobalSymbol(GV);

+ 9 - 2
lib/HLSL/DxilLinker.cpp

@@ -481,8 +481,8 @@ bool IsMatchedType(Type *Ty0, Type *Ty) {
 bool DxilLinkJob::AddResource(DxilResourceBase *res, llvm::GlobalVariable *GV) {
   if (m_resourceMap.count(res->GetGlobalName())) {
     DxilResourceBase *res0 = m_resourceMap[res->GetGlobalName()].first;
-    Type *Ty0 = res0->GetGlobalSymbol()->getType()->getPointerElementType();
-    Type *Ty = res->GetGlobalSymbol()->getType()->getPointerElementType();
+    Type *Ty0 = res0->GetHLSLType()->getPointerElementType();
+    Type *Ty = res->GetHLSLType()->getPointerElementType();
     // Make sure res0 match res.
     bool bMatch = IsMatchedType(Ty0, Ty);
     if (!bMatch) {
@@ -1217,6 +1217,10 @@ void DxilLinkJob::FixShaderModelMismatch(llvm::Module &M) {
 void DxilLinkJob::RunPreparePass(Module &M) {
   StripDeadDebugInfo(M);
   FixShaderModelMismatch(M);
+
+  DxilModule &DM = M.GetDxilModule();
+  const ShaderModel *pSM = DM.GetShaderModel();
+
   legacy::PassManager PM;
   PM.add(createAlwaysInlinerPass(/*InsertLifeTime*/ false));
 
@@ -1247,6 +1251,9 @@ void DxilLinkJob::RunPreparePass(Module &M) {
   PM.add(createDeadCodeEliminationPass());
   PM.add(createGlobalDCEPass());
 
+  if (pSM->IsSM66Plus() && pSM->IsLib())
+    PM.add(createDxilMutateResourceToHandlePass());
+
   PM.add(createDxilLowerCreateHandleForLibPass());
   PM.add(createDxilTranslateRawBuffer());
   PM.add(createDxilFinalizeModulePass());

+ 1 - 1
lib/HLSL/DxilPatchShaderRecordBindings.cpp

@@ -777,7 +777,7 @@ bool DxilPatchShaderRecordBindings::GetHandleInfo(
     shaderRegister = Resource->GetLowerBound();
     kind = Resource->GetKind();
     resClass = Resource->GetClass();
-    resType = Resource->GetGlobalSymbol()->getType()->getPointerElementType();
+    resType = Resource->GetHLSLType()->getPointerElementType();
   }
   return Resource != nullptr;
 }

+ 481 - 0
lib/HLSL/DxilPromoteResourcePasses.cpp

@@ -10,15 +10,25 @@
 #include "dxc/DXIL/DxilUtil.h"
 #include "dxc/HLSL/DxilGenerationPass.h"
 #include "dxc/HLSL/HLModule.h"
+#include "dxc/DXIL/DxilResourceBase.h"
+#include "dxc/DXIL/DxilResource.h"
+#include "dxc/DXIL/DxilCBuffer.h"
+#include "dxc/DXIL/DxilOperations.h"
+#include "dxc/DXIL/DxilModule.h"
 #include "llvm/Pass.h"
 #include "llvm/Analysis/AssumptionCache.h"
+#include "llvm/ADT/DenseSet.h"
 #include "llvm/IR/Dominators.h"
 #include "llvm/IR/Function.h"
 #include "llvm/IR/Instruction.h"
 #include "llvm/IR/Instructions.h"
+#include "llvm/IR/Intrinsics.h"
 #include "llvm/IR/LLVMContext.h"
 #include "llvm/IR/Module.h"
+#include "llvm/IR/Attributes.h"
+#include "llvm/IR/DebugInfo.h"
 #include "llvm/IR/Operator.h"
+
 #include "llvm/Transforms/Utils/PromoteMemToReg.h"
 #include "llvm/Transforms/Utils/SSAUpdater.h"
 #include <unordered_set>
@@ -223,3 +233,474 @@ ModulePass *llvm::createDxilPromoteStaticResources() {
 INITIALIZE_PASS(DxilPromoteStaticResources,
                 "hlsl-dxil-promote-static-resources",
                 "DXIL promote static resource use", false, false)
+
+// Mutate high-level resource type into handle.
+// This is used for SM 6.6+, on libraries only, where
+// CreateHandleForLib is eliminated, and high-level resource
+// types are only preserved in metadata for reflection purposes.
+namespace {
+// Overview
+// 1. collectCandidates - collect to MutateValSet
+//    Start from resource global variable, function parameter/ret, alloca.
+//    Propagate to all insts, GEP/ld/st/phi/select/called functions.
+// 2. mutateCandidates
+//    Mutate all non-function value types.
+//    Mutate functions by creating new function with new type, then
+//    splice original function blocks into new function, and
+//    replace old argument uses with new function's arguments.
+class DxilMutateResourceToHandle : public ModulePass {
+public:
+  static char ID; // Pass identification, replacement for typeid
+  explicit DxilMutateResourceToHandle() : ModulePass(ID) {}
+
+  const char *getPassName() const override {
+    return "DXIL Mutate resource to handle";
+  }
+
+  bool runOnModule(Module &M) override {
+    if (M.HasHLModule()) {
+      auto &HLM = M.GetHLModule();
+      if (!HLM.GetShaderModel()->IsSM66Plus())
+        return false;
+
+      hdlTy = HLM.GetOP()->GetHandleType();
+      pTypeSys = &HLM.GetTypeSystem();
+    } else if (M.HasDxilModule()) {
+      auto &DM = M.GetDxilModule();
+      if (!DM.GetShaderModel()->IsSM66Plus())
+        return false;
+
+      hdlTy = DM.GetOP()->GetHandleType();
+      pTypeSys = &DM.GetTypeSystem();
+    } else {
+      return false;
+    }
+    collectCandidates(M);
+    mutateCandidates(M);
+    // Remvoe cast to handle.
+    return !MutateValSet.empty();
+  }
+
+private:
+  Type *mutateToHandleTy(Type *Ty);
+  bool mutateTypesToHandleTy(SmallVector<Type *, 4> &Tys);
+
+  void collectGlobalResource(DxilResourceBase *Res,
+                             SmallVector<Value *, 8> &WorkList);
+  void collectAlloca(Function &F, SmallVector<Value *, 8> &WorkList);
+
+  SmallVector<Value *, 8> collectHlslObjects(Module &M);
+
+  void collectCandidates(Module &M);
+  void mutateCandidates(Module &M);
+
+  Type *hdlTy;
+  DxilTypeSystem *pTypeSys;
+  DenseSet<Value *> MutateValSet;
+  DenseMap<Type *, Type *> MutateTypeMap;
+};
+
+char DxilMutateResourceToHandle::ID = 0;
+
+Type *DxilMutateResourceToHandle::mutateToHandleTy(Type *Ty) {
+  auto it = MutateTypeMap.find(Ty);
+  if (it != MutateTypeMap.end())
+    return it->second;
+
+  Type *ResultTy = nullptr;
+  if (ArrayType *AT = dyn_cast<ArrayType>(Ty)) {
+    SmallVector<unsigned, 2> nestedSize;
+    Type *EltTy = Ty;
+    while (ArrayType *NestAT = dyn_cast<ArrayType>(EltTy)) {
+      nestedSize.emplace_back(NestAT->getNumElements());
+      EltTy = NestAT->getElementType();
+    }
+    Type *mutatedTy = mutateToHandleTy(EltTy);
+    if (mutatedTy == EltTy) {
+      ResultTy = Ty;
+    } else {
+      Type *newAT = mutatedTy;
+      for (auto it = nestedSize.rbegin(), E = nestedSize.rend(); it != E; ++it)
+        newAT = ArrayType::get(newAT, *it);
+      ResultTy = newAT;
+    }
+  } else if (PointerType *PT = dyn_cast<PointerType>(Ty)) {
+    Type *EltTy = PT->getElementType();
+    Type *mutatedTy = mutateToHandleTy(EltTy);
+    if (mutatedTy == EltTy)
+      ResultTy = Ty;
+    else
+      ResultTy = mutatedTy->getPointerTo(PT->getAddressSpace());
+  } else if (dxilutil::IsHLSLResourceType(Ty)) {
+    ResultTy = hdlTy;
+  } else if (StructType *ST = dyn_cast<StructType>(Ty)) {
+    if (!ST->isOpaque()) {
+      SmallVector<Type *, 4> Elts(ST->element_begin(), ST->element_end());
+      if (!mutateTypesToHandleTy(Elts)) {
+        ResultTy = Ty;
+      } else {
+        ResultTy = StructType::create(Elts, ST->getName().str() + ".hdl");
+      }
+    } else {
+      if (ST->getName() == "ConstantBuffer")
+        ResultTy = hdlTy;
+      else
+        ResultTy = Ty;
+    }
+  } else if (FunctionType *FT = dyn_cast<FunctionType>(Ty)) {
+    Type *RetTy = FT->getReturnType();
+    SmallVector<Type *, 4> Args(FT->param_begin(), FT->param_end());
+    Type *mutatedRetTy = mutateToHandleTy(RetTy);
+    if (!mutateTypesToHandleTy(Args) && RetTy == mutatedRetTy) {
+      ResultTy = Ty;
+    } else {
+      ResultTy = FunctionType::get(mutatedRetTy, Args, FT->isVarArg());
+    }
+  } else {
+    ResultTy = Ty;
+  }
+  MutateTypeMap[Ty] = ResultTy;
+  return ResultTy;
+}
+
+bool DxilMutateResourceToHandle::mutateTypesToHandleTy(
+    SmallVector<Type *, 4> &Tys) {
+  bool bMutated = false;
+  for (size_t i = 0; i < Tys.size(); i++) {
+    Type *Ty = Tys[i];
+    Type *mutatedTy = mutateToHandleTy(Ty);
+    if (Ty != mutatedTy) {
+      Tys[i] = mutatedTy;
+      bMutated = true;
+    }
+  }
+  return bMutated;
+}
+
+void DxilMutateResourceToHandle::collectGlobalResource(
+    DxilResourceBase *Res, SmallVector<Value *, 8> &WorkList) {
+  Value *GV = Res->GetGlobalSymbol();
+  // Save hlsl type before mutate to handle.
+  Res->SetHLSLType(GV->getType());
+  mutateToHandleTy(GV->getType());
+  WorkList.emplace_back(GV);
+}
+void DxilMutateResourceToHandle::collectAlloca(
+    Function &F, SmallVector<Value *, 8> &WorkList) {
+  if (F.isDeclaration())
+    return;
+  for (Instruction &I : F.getEntryBlock()) {
+    AllocaInst *AI = dyn_cast<AllocaInst>(&I);
+    if (!AI)
+      continue;
+    Type *Ty = AI->getType();
+    Type *MTy = mutateToHandleTy(Ty);
+    if (Ty == MTy)
+      continue;
+    WorkList.emplace_back(AI);
+  }
+}
+
+}
+
+SmallVector<Value *, 8>
+DxilMutateResourceToHandle::collectHlslObjects(Module &M) {
+  // Add all global/function/argument/alloca has resource type.
+  SmallVector<Value *, 8> WorkList;
+
+  // Assume this is after SROA so no struct for global/alloca.
+
+  // Functions.
+  for (Function &F : M) {
+    collectAlloca(F, WorkList);
+    FunctionType *FT = F.getFunctionType();
+    FunctionType *MFT = cast<FunctionType>(mutateToHandleTy(FT));
+    if (FT == MFT)
+      continue;
+    WorkList.emplace_back(&F);
+    // Check args.
+    for (Argument &Arg : F.args()) {
+      Type *Ty = Arg.getType();
+      Type *MTy = mutateToHandleTy(Ty);
+      if (Ty == MTy)
+        continue;
+      WorkList.emplace_back(&Arg);
+    }
+  }
+
+  // Static globals.
+  for (GlobalVariable &GV : M.globals()) {
+    if (!dxilutil::IsStaticGlobal(&GV))
+      continue;
+    Type *Ty = dxilutil::GetArrayEltTy(GV.getValueType());
+    if (!dxilutil::IsHLSLObjectType(Ty))
+      continue;
+    WorkList.emplace_back(&GV);
+  }
+
+  // Global resources.
+  if (M.HasHLModule()) {
+    auto &HLM = M.GetHLModule();
+    for (auto &Res : HLM.GetCBuffers()) {
+      collectGlobalResource(Res.get(), WorkList);
+    }
+    for (auto &Res : HLM.GetSRVs()) {
+      collectGlobalResource(Res.get(), WorkList);
+    }
+    for (auto &Res : HLM.GetUAVs()) {
+      collectGlobalResource(Res.get(), WorkList);
+    }
+    for (auto &Res : HLM.GetSamplers()) {
+      collectGlobalResource(Res.get(), WorkList);
+    }
+  } else {
+    auto &DM = M.GetDxilModule();
+    for (auto &Res : DM.GetCBuffers()) {
+      collectGlobalResource(Res.get(), WorkList);
+    }
+    for (auto &Res : DM.GetSRVs()) {
+      collectGlobalResource(Res.get(), WorkList);
+    }
+    for (auto &Res : DM.GetUAVs()) {
+      collectGlobalResource(Res.get(), WorkList);
+    }
+    for (auto &Res : DM.GetSamplers()) {
+      collectGlobalResource(Res.get(), WorkList);
+    }
+  }
+  return WorkList;
+}
+
+void DxilMutateResourceToHandle::collectCandidates(Module &M) {
+  SmallVector<Value *, 8> WorkList = collectHlslObjects(M);
+
+  // Propagate candidates.
+  while (!WorkList.empty()) {
+    Value *V = WorkList.pop_back_val();
+    MutateValSet.insert(V);
+
+    for (User *U : V->users()) {
+      // collect in a user.
+      SmallVector<Value *, 2> newCandidates;
+      // Should only used by ld/st/sel/phi/gep/call.
+      if (LoadInst *LI = dyn_cast<LoadInst>(U)) {
+        newCandidates.emplace_back(LI);
+      } else if (StoreInst *SI = dyn_cast<StoreInst>(U)) {
+        Value *Ptr = SI->getPointerOperand();
+        Value *Val = SI->getValueOperand();
+        if (V == Ptr)
+          newCandidates.emplace_back(Val);
+        else
+          newCandidates.emplace_back(Ptr);
+      } else if (GEPOperator *GEP = dyn_cast<GEPOperator>(U)) {
+        // If result type of GEP not related to resource type, skip.
+        Type *Ty = GEP->getType();
+        Type *MTy = mutateToHandleTy(Ty);
+        if (MTy == Ty)
+          continue;
+        newCandidates.emplace_back(GEP);
+      } else if (PHINode *Phi = dyn_cast<PHINode>(U)) {
+        // Propagate all operands.
+        newCandidates.emplace_back(Phi);
+        for (Use &PhiOp : Phi->incoming_values()) {
+          if (V == PhiOp)
+            continue;
+          newCandidates.emplace_back(PhiOp);
+        }
+      } else if (SelectInst *Sel = dyn_cast<SelectInst>(U)) {
+        // Propagate other result.
+        newCandidates.emplace_back(Sel);
+        Value *TrueV = Sel->getTrueValue();
+        Value *FalseV = Sel->getFalseValue();
+        if (TrueV == V)
+          newCandidates.emplace_back(FalseV);
+        else
+          newCandidates.emplace_back(TrueV);
+      } else if (BitCastOperator *BCO = dyn_cast<BitCastOperator>(U)) {
+        // Make sure only used for lifetime intrinsic.
+        for (User *BCUser : BCO->users()) {
+          if (ConstantArray *CA = dyn_cast<ConstantArray>(BCUser)) {
+            // For llvm.used.
+            if (CA->hasOneUse()) {
+              Value *CAUser = CA->user_back();
+              if (GlobalVariable *GV = dyn_cast<GlobalVariable>(CAUser)) {
+                if (GV->getName() == "llvm.used")
+                  continue;
+              }
+            } else if (CA->user_empty()) {
+              continue;
+            }
+          }
+          CallInst *CI = cast<CallInst>(BCUser);
+          Function *F = CI->getCalledFunction();
+          Intrinsic::ID ID = F->getIntrinsicID();
+          if (ID != Intrinsic::lifetime_start &&
+              ID != Intrinsic::lifetime_end) {
+            DXASSERT(false, "unexpected resource object user");
+          }
+        }
+      } else {
+        CallInst *CI = cast<CallInst>(U);
+        Type *Ty = CI->getType();
+        Type *MTy = mutateToHandleTy(Ty);
+        if (Ty != MTy)
+          newCandidates.emplace_back(CI);
+
+        SmallVector<Value *, 4> Args(CI->arg_operands().begin(),
+                                     CI->arg_operands().end());
+        for (Value *Arg : Args) {
+          if (Arg == V)
+            continue;
+          Type *Ty = Arg->getType();
+          Type *MTy = mutateToHandleTy(Ty);
+          if (Ty == MTy)
+            continue;
+          newCandidates.emplace_back(Arg);
+        }
+      }
+
+      for (Value *Val : newCandidates) {
+        // New candidate find.
+        if (MutateValSet.insert(Val).second) {
+          WorkList.emplace_back(Val);
+        }
+      }
+    }
+  }
+}
+
+void DxilMutateResourceToHandle::mutateCandidates(Module &M) {
+  SmallVector<Function *, 2> CandidateFns;
+  for (Value *V : MutateValSet) {
+    if (Function *F = dyn_cast<Function>(V)) {
+      CandidateFns.emplace_back(F);
+      continue;
+    }
+    Type *Ty = V->getType();
+    V->dump();
+    Type *MTy = mutateToHandleTy(Ty);
+    if (AllocaInst *AI = dyn_cast<AllocaInst>(V)) {
+      AI->setAllocatedType(MTy->getPointerElementType());
+    } else if (GetElementPtrInst *GEP = dyn_cast<GetElementPtrInst>(V)) {
+      Type *MResultEltTy = mutateToHandleTy(GEP->getResultElementType());
+      GEP->setResultElementType(MResultEltTy);
+      Type *MSrcEltTy = mutateToHandleTy(GEP->getSourceElementType());
+      GEP->setSourceElementType(MSrcEltTy);
+    } else if (GEPOperator *GEPO = dyn_cast<GEPOperator>(V)) {
+      // GEP operator not support setSourceElementType.
+      // Create a new GEP here.
+      Constant *C = cast<Constant>(GEPO->getPointerOperand());
+      IRBuilder<> B(C->getContext());
+      // Make sure C is mutated so the GEP get correct sourceElementType.
+      C->mutateType(mutateToHandleTy(C->getType()));
+
+      // Collect user of GEPs, then replace all use with undef.
+      SmallVector<Use *, 2> Uses;
+      for (Use &U : GEPO->uses()) {
+        Uses.emplace_back(&U);
+      }
+
+      SmallVector<Value *, 2> idxList(GEPO->idx_begin(), GEPO->idx_end());
+      Type *Ty = GEPO->getType();
+      GEPO->replaceAllUsesWith(UndefValue::get(Ty));
+      StringRef Name = GEPO->getName();
+
+      // GO and newGO will be same constant except has different
+      // sourceElementType. ConstantMap think they're the same constant. Have to
+      // remove GO first before create newGO.
+      C->removeDeadConstantUsers();
+
+      Value *newGO = B.CreateGEP(C, idxList, Name);
+      // update uses.
+      for (Use *U : Uses) {
+        U->set(newGO);
+      }
+      continue;
+    }
+    V->mutateType(MTy);
+    V->dump();
+  }
+
+  Function *createHandleForLibOnHandle = nullptr;
+  hlsl::OP *hlslOP = nullptr;
+  if (M.HasDxilModule()) {
+    auto &DM = M.GetDxilModule();
+    hlslOP = DM.GetOP();
+    if (hlslOP->IsDxilOpUsed(DXIL::OpCode::CreateHandleForLib)) {
+      createHandleForLibOnHandle =
+          hlslOP->GetOpFunc(DXIL::OpCode::CreateHandleForLib, hdlTy);
+    }
+  }
+
+  // Mutate functions.
+  for (Function *F : CandidateFns) {
+    Function *MF = nullptr;
+    if (hlslOP) {
+      if (hlslOP->IsDxilOpFunc(F)) {
+        DXIL::OpCodeClass OpcodeClass;
+        if (hlslOP->GetOpCodeClass(F, OpcodeClass)) {
+          if (OpcodeClass == DXIL::OpCodeClass::CreateHandleForLib) {
+            MF = createHandleForLibOnHandle;
+          }
+        }
+      }
+    }
+
+    if (!MF) {
+      FunctionType *FT = F->getFunctionType();
+      FunctionType *MFT = cast<FunctionType>(MutateTypeMap[FT]);
+
+      MF = Function::Create(MFT, F->getLinkage(), "", &M);
+      MF->takeName(F);
+
+      // Copy calling conv.
+      MF->setCallingConv(F->getCallingConv());
+      // Copy attributes.
+      AttributeSet AS = F->getAttributes();
+      MF->setAttributes(AS);
+      // Annotation.
+      if (DxilFunctionAnnotation *FnAnnot =
+              pTypeSys->GetFunctionAnnotation(F)) {
+        DxilFunctionAnnotation *newFnAnnot =
+            pTypeSys->AddFunctionAnnotation(MF);
+        DxilParameterAnnotation &RetAnnot = newFnAnnot->GetRetTypeAnnotation();
+        RetAnnot = FnAnnot->GetRetTypeAnnotation();
+        for (unsigned i = 0; i < FnAnnot->GetNumParameters(); i++) {
+          newFnAnnot->GetParameterAnnotation(i) =
+              FnAnnot->GetParameterAnnotation(i);
+        }
+      }
+      // Update function debug info.
+      if (DISubprogram *funcDI = getDISubprogram(F))
+        funcDI->replaceFunction(MF);
+    }
+
+    for (auto it = F->user_begin(); it != F->user_end();) {
+      CallInst *CI = cast<CallInst>(*(it++));
+      CI->setCalledFunction(MF);
+    }
+
+    if (F->isDeclaration()) {
+      F->eraseFromParent();
+      continue;
+    }
+    // Take body of F.
+    // Splice the body of the old function right into the new function.
+    MF->getBasicBlockList().splice(MF->begin(), F->getBasicBlockList());
+    // Replace use of arg.
+    auto argIt = F->arg_begin();
+    for (auto MArgIt = MF->arg_begin(); MArgIt != MF->arg_end();) {
+      Argument *Arg = (argIt++);
+      Argument *MArg = (MArgIt++);
+      Arg->replaceAllUsesWith(MArg);
+    }
+  }
+}
+
+ModulePass *llvm::createDxilMutateResourceToHandlePass() {
+  return new DxilMutateResourceToHandle();
+}
+
+INITIALIZE_PASS(DxilMutateResourceToHandle,
+                "hlsl-dxil-resources-to-handle",
+                "Mutate resource to handle", false, false)

+ 10 - 3
lib/HLSL/DxilValidation.cpp

@@ -388,6 +388,7 @@ struct ValidationContext {
   Module &M;
   Module *pDebugModule;
   DxilModule &DxilMod;
+  const Type *HandleTy;
   const DataLayout &DL;
   DebugLoc LastDebugLocEmit;
   ValidationRule LastRuleEmit;
@@ -421,6 +422,7 @@ struct ValidationContext {
         kLLVMLoopMDKind(llvmModule.getContext().getMDKindID("llvm.loop")),
         slotTracker(&llvmModule, true) {
     DxilMod.GetDxilVersion(m_DxilMajor, m_DxilMinor);
+    HandleTy = DxilMod.GetOP()->GetHandleType();
 
     for (Function &F : llvmModule.functions()) {
       if (DxilMod.HasDxilEntryProps(&F)) {
@@ -481,6 +483,9 @@ struct ValidationContext {
           }
         } else if (LoadInst *LI = dyn_cast<LoadInst>(U)) {
           PropagateResMap(U, Res);
+        } else if (isa<BitCastOperator>(U) && U->user_empty()) {
+          // For hlsl type.
+          continue;
         } else {
           EmitResourceError(Res, ValidationRule::InstrResourceUser);
         }
@@ -570,8 +575,7 @@ struct ValidationContext {
           }
 
           ConstantInt *cIndex = dyn_cast<ConstantInt>(hdl.get_index());
-          if (!Res->GetGlobalSymbol()
-                   ->getType()
+          if (!Res->GetHLSLType()
                    ->getPointerElementType()
                    ->isArrayTy()) {
             if (!cIndex) {
@@ -2722,6 +2726,9 @@ static bool ValidateType(Type *Ty, ValidationContext &ValCtx, bool bInner = fals
 
     StringRef Name = ST->getName();
     if (Name.startswith("dx.")) {
+      // Allow handle type.
+      if (ValCtx.HandleTy == Ty)
+        return true;
       hlsl::OP *hlslOP = ValCtx.DxilMod.GetOP();
       if (IsDxilBuiltinStructType(ST, hlslOP)) {
         ValCtx.EmitTypeError(Ty, ValidationRule::InstrDxilStructUser);
@@ -4128,7 +4135,7 @@ CollectCBufferRanges(DxilStructAnnotation *annotation,
 }
 
 static void ValidateCBuffer(DxilCBuffer &cb, ValidationContext &ValCtx) {
-  Type *Ty = cb.GetGlobalSymbol()->getType()->getPointerElementType();
+  Type *Ty = cb.GetHLSLType()->getPointerElementType();
   if (cb.GetRangeSize() != 1 || Ty->isArrayTy()) {
     Ty = Ty->getArrayElementType();
   }

+ 3 - 0
lib/Transforms/IPO/PassManagerBuilder.cpp

@@ -278,6 +278,7 @@ static void addHLSLPasses(bool HLSLHighLevel, unsigned OptLevel, bool OnlyWarnOn
 
   MPM.add(createDxilPromoteLocalResources());
   MPM.add(createDxilPromoteStaticResources());
+
   // Verify no undef resource again after promotion
   MPM.add(createInvalidateUndefResourcesPass());
 
@@ -374,6 +375,7 @@ void PassManagerBuilder::populateModulePassManager(
       MPM.add(createMultiDimArrayToOneDimArrayPass());
       MPM.add(createDeadCodeEliminationPass());
       MPM.add(createGlobalDCEPass());
+      MPM.add(createDxilMutateResourceToHandlePass());
       MPM.add(createDxilLowerCreateHandleForLibPass());
       MPM.add(createDxilTranslateRawBuffer());
       MPM.add(createDxilLegalizeSampleOffsetPass());
@@ -675,6 +677,7 @@ void PassManagerBuilder::populateModulePassManager(
     MPM.add(createDxilRemoveDeadBlocksPass());
     MPM.add(createDeadCodeEliminationPass());
     MPM.add(createGlobalDCEPass());
+    MPM.add(createDxilMutateResourceToHandlePass());
     MPM.add(createDxilLowerCreateHandleForLibPass());
     MPM.add(createDxilTranslateRawBuffer());
     // Always try to legalize sample offsets as loop unrolling

+ 3 - 4
tools/clang/lib/CodeGen/CGHLSLMSFinishCodeGen.cpp

@@ -1805,7 +1805,7 @@ unsigned AllocateDxilConstantBuffer(
       continue;
 
     unsigned size = C->GetRangeSize();
-    llvm::Type *Ty = C->GetGlobalSymbol()->getType()->getPointerElementType();
+    llvm::Type *Ty = C->GetHLSLType()->getPointerElementType();
     auto fieldAnnotation = constVarAnnotationMap.at(C->GetGlobalSymbol());
     bool bRowMajor = HLMatrixType::isa(Ty)
                          ? fieldAnnotation.GetMatrixAnnotation().Orientation ==
@@ -1906,7 +1906,7 @@ bool CreateCBufferVariable(HLCBuffer &CB, HLModule &HLM, llvm::Type *HandleTy) {
     if (!GV->use_empty())
       bUsed = true;
     // Global variable must be pointer type.
-    llvm::Type *Ty = GV->getType()->getPointerElementType();
+    llvm::Type *Ty = C->GetHLSLType()->getPointerElementType();
     Elements.emplace_back(Ty);
   }
   // Don't create CBuffer variable for unused cbuffer.
@@ -1942,9 +1942,8 @@ bool CreateCBufferVariable(HLCBuffer &CB, HLModule &HLM, llvm::Type *HandleTy) {
     // array.
     DXASSERT(CB.GetConstants().size() == 1,
              "ConstantBuffer should have 1 constant");
-    Value *GV = CB.GetConstants()[0]->GetGlobalSymbol();
     llvm::Type *CBEltTy =
-        GV->getType()->getPointerElementType()->getArrayElementType();
+        CB.GetConstants()[0]->GetHLSLType()->getPointerElementType()->getArrayElementType();
     cbIndexDepth = 1;
     while (CBEltTy->isArrayTy()) {
       CBEltTy = CBEltTy->getArrayElementType();

+ 2 - 2
tools/clang/test/HLSLFileCheck/hlsl/objects/Buffer/res_select2_x.hlsl

@@ -1,8 +1,8 @@
 // RUN: %dxc -T lib_6_x -auto-binding-space 11 %s | FileCheck %s
 
 // lib_6_x does not reduce phi/select of resource or handle in lib.
-// CHECK: phi %"class.RWBuffer
-// CHECK: select i1 %{{[^,]+}}, %"class.
+// CHECK: phi %dx.types.Handle
+// CHECK: select i1 %{{[^,]+}}, %dx.types.Handle
 // CHECK: ret <4 x float>
 
 RWBuffer<float4> BufArray[2][2][3];

+ 7 - 8
tools/clang/test/HLSLFileCheck/hlsl/objects/Buffer/res_select5_x.hlsl

@@ -4,14 +4,13 @@
 // phi/select of handle should not be produced in this case, but would be allowed if it were.
 
 // CHECK: define <4 x float> @"\01?test@@YA?AV?$vector@M$03@@HHH@Z"(i32 %i, i32 %j, i32 %m)
-// CHECK-NOT: phi %dx.types.Handle
-// CHECK-NOT: select i1 %{{[^,]+}}, %dx.types.Handle
-// CHECK: phi %"class.
-// CHECK-NOT: phi %dx.types.Handle
-// CHECK-NOT: select i1 %{{[^,]+}}, %dx.types.Handle
-// CHECK: select i1 %{{[^,]+}}, %"class.
-// CHECK-NOT: phi %dx.types.Handle
-// CHECK-NOT: select i1 %{{[^,]+}}, %dx.types.Handle
+
+// CHECK: phi %dx.types.Handle
+// CHECK: phi %dx.types.Handle
+// CHECK: phi %dx.types.Handle
+// CHECK: select i1 %{{[^,]+}}, %dx.types.Handle
+// CHECK: phi %dx.types.Handle
+
 // CHECK: ret <4 x float>
 
 RWBuffer<float4> BufArray[2][2][3];

+ 5 - 8
tools/clang/test/HLSLFileCheck/hlsl/objects/StructuredBuffer/res_select3_x.hlsl

@@ -4,14 +4,11 @@
 // phi/select of handle should not be produced in this case, but would be allowed if it were.
 
 // CHECK: define i32 @"\01?test@@YAIHHH@Z"(i32 %i, i32 %j, i32 %m)
-// CHECK-NOT: phi %dx.types.Handle
-// CHECK-NOT: select i1 %{{[^,]+}}, %dx.types.Handle
-// CHECK: phi %"class.
-// CHECK-NOT: phi %dx.types.Handle
-// CHECK-NOT: select i1 %{{[^,]+}}, %dx.types.Handle
-// CHECK: select i1 %{{[^,]+}}, %"class.
-// CHECK-NOT: phi %dx.types.Handle
-// CHECK-NOT: select i1 %{{[^,]+}}, %dx.types.Handle
+
+// CHECK: phi %dx.types.Handle
+// CHECK: select i1 %{{[^,]+}}, %dx.types.Handle
+// CHECK: phi %dx.types.Handle
+// CHECK: select i1 %{{[^,]+}}, %dx.types.Handle
 
 // Make sure get dimensions returns 24
 // CHECK: ret i32 24

+ 5 - 8
tools/clang/test/HLSLFileCheck/hlsl/objects/StructuredBuffer/res_select4_x.hlsl

@@ -4,14 +4,11 @@
 // phi/select of handle should not be produced in this case, but would be allowed if it were.
 
 // CHECK: define i32 @"\01?test@@YAIHHH@Z"(i32 %i, i32 %j, i32 %m)
-// CHECK-NOT: phi %dx.types.Handle
-// CHECK-NOT: select i1 %{{[^,]+}}, %dx.types.Handle
-// CHECK: phi %"class.
-// CHECK-NOT: phi %dx.types.Handle
-// CHECK-NOT: select i1 %{{[^,]+}}, %dx.types.Handle
-// CHECK: select i1 %{{[^,]+}}, %"class.
-// CHECK-NOT: phi %dx.types.Handle
-// CHECK-NOT: select i1 %{{[^,]+}}, %dx.types.Handle
+// CHECK: phi %dx.types.Handle
+// CHECK: phi %dx.types.Handle
+// CHECK: select i1 %{{[^,]+}}, %dx.types.Handle
+// CHECK: phi %dx.types.Handle
+// CHECK: select i1 %{{[^,]+}}, %dx.types.Handle
 
 // Make sure get dimensions returns 24
 // CHECK: ret i32 24

+ 10 - 6
tools/clang/test/HLSLFileCheck/shader_targets/library/lib_res_param_x.hlsl

@@ -1,12 +1,16 @@
 // RUN: %dxc -T lib_6_x  %s | FileCheck %s
 
 // resources in return/params allowed for lib_6_x
-// CHECK: alloca %struct.T
-// CHECK: store %struct.RWByteAddressBuffer
-// CHECK: call void @"\01?resStruct@@YA?AUT2@@UT@@V?$vector@I$01@@@Z"(%struct.T2
-// CHECK: %[[ptr:[^, ]+]] = getelementptr inbounds %struct.T2
-// CHECK: %[[val:[^, ]+]] = load %"class.RWStructuredBuffer<D>", %"class.RWStructuredBuffer<D>"* %[[ptr]]
-// CHECK: call %dx.types.Handle @"dx.op.createHandleForLib.class.RWStructuredBuffer<D>"(i32 160, %"class.RWStructuredBuffer<D>" %[[val]])
+// CHECK: alloca %struct.T.hdl
+// CHECK: store %dx.types.Handle
+// CHECK: call void @"\01?resStruct@@YA?AUT2@@UT@@V?$vector@I$01@@@Z"(%struct.T2.hdl
+// CHECK: %[[ptr:[^, ]+]] = getelementptr inbounds %struct.T2.hdl
+// CHECK: %[[val:[^, ]+]] = load %dx.types.Handle, %dx.types.Handle* %[[ptr]]
+// CHECK: call %dx.types.Handle @dx.op.createHandleForLib.dx.types.Handle(i32 160, %dx.types.Handle %[[val]])
+
+// Make sure save bitcast for global symbol and HLSL type.
+// CHECK:i32 0, %struct.RWByteAddressBuffer* bitcast (%dx.types.Handle* @"\01?outputBuffer@@3URWByteAddressBuffer@@A" to %struct.RWByteAddressBuffer*), !"outputBuffer"
+// CHECK:i32 1, %struct.RWByteAddressBuffer* bitcast (%dx.types.Handle* @"\01?outputBuffer2@@3URWByteAddressBuffer@@A" to %struct.RWByteAddressBuffer*), !"outputBuffer2"
 
 
 struct T {

+ 1 - 1
tools/clang/test/HLSLFileCheck/shader_targets/library/lib_select_res_x.hlsl

@@ -1,7 +1,7 @@
 // RUN: %dxc -T lib_6_x -Od %s | FileCheck %s
 
 // lib_6_x allows phi on resource, targeting offline linking only.
-// CHECK: phi %struct.ByteAddressBuffer
+// CHECK: phi %dx.types.Handle
 
 ByteAddressBuffer firstBuffer, secondBuffer;
 uint firstBufferSize;

+ 1 - 1
tools/clang/test/HLSLFileCheck/shader_targets/library/lib_select_res_x2.hlsl

@@ -1,7 +1,7 @@
 // RUN: %dxc -T lib_6_x -auto-binding-space 11 %s | FileCheck %s
 
 // lib_6_x allows select on resource, targeting offline linking only.
-// CHECK: select i1 %{{[^, ]+}}, %struct.ByteAddressBuffer
+// CHECK: select i1 %{{[^, ]+}}, %dx.types.Handle
 
 RWByteAddressBuffer outputBuffer : register(u0);
 ByteAddressBuffer ReadBuffer : register(t0);

+ 3 - 3
tools/clang/tools/dxcompiler/dxcdisassembler.cpp

@@ -954,7 +954,7 @@ void PrintStructBufferDefinition(DxilResource *buf,
   llvm::Type *RetTy = buf->GetRetType();
   // Skip none struct type.
   if (!RetTy->isStructTy() || HLMatrixType::isa(RetTy)) {
-    llvm::Type *Ty = buf->GetGlobalSymbol()->getType()->getPointerElementType();
+    llvm::Type *Ty = buf->GetHLSLType()->getPointerElementType();
     // For resource array, use element type.
     if (Ty->isArrayTy())
       Ty = Ty->getArrayElementType();
@@ -993,7 +993,7 @@ void PrintStructBufferDefinition(DxilResource *buf,
 void PrintTBufferDefinition(DxilResource *buf, DxilTypeSystem &typeSys,
                                    raw_string_ostream &OS, StringRef comment) {
   const unsigned offsetIndent = 50;
-  llvm::Type *Ty = buf->GetGlobalSymbol()->getType()->getPointerElementType();
+  llvm::Type *Ty = buf->GetHLSLType()->getPointerElementType();
   // For TextureBuffer<> buf[2], the array size is in Resource binding count
   // part.
   if (Ty->isArrayTy())
@@ -1019,7 +1019,7 @@ void PrintTBufferDefinition(DxilResource *buf, DxilTypeSystem &typeSys,
 void PrintCBufferDefinition(DxilCBuffer *buf, DxilTypeSystem &typeSys,
                                    raw_string_ostream &OS, StringRef comment) {
   const unsigned offsetIndent = 50;
-  llvm::Type *Ty = buf->GetGlobalSymbol()->getType()->getPointerElementType();
+  llvm::Type *Ty = buf->GetHLSLType()->getPointerElementType();
   // For ConstantBuffer<> buf[2], the array size is in Resource binding count
   // part.
   if (Ty->isArrayTy())

+ 7 - 6
tools/clang/unittests/HLSL/LinkerTest.cpp

@@ -307,14 +307,15 @@ TEST_F(LinkerTest, RunLinkGlobalInit) {
 }
 
 TEST_F(LinkerTest, RunLinkFailReDefineGlobal) {
+  LPCWSTR option[] = { L"-default-linkage", L"external" };
   CComPtr<IDxcBlob> pEntryLib;
-  CompileLib(L"..\\CodeGenHLSL\\lib_global2.hlsl", &pEntryLib);
+  CompileLib(L"..\\CodeGenHLSL\\lib_global2.hlsl", &pEntryLib, option, L"lib_6_3");
 
   CComPtr<IDxcBlob> pLib0;
-  CompileLib(L"..\\CodeGenHLSL\\lib_global3.hlsl", &pLib0);
+  CompileLib(L"..\\CodeGenHLSL\\lib_global3.hlsl", &pLib0, option, L"lib_6_3");
 
   CComPtr<IDxcBlob> pLib1;
-  CompileLib(L"..\\CodeGenHLSL\\lib_global4.hlsl", &pLib1);
+  CompileLib(L"..\\CodeGenHLSL\\lib_global4.hlsl", &pLib1, option, L"lib_6_3");
 
   CComPtr<IDxcLinker> pLinker;
   CreateLinker(&pLinker);
@@ -688,14 +689,14 @@ TEST_F(LinkerTest, RunLinkToLibWithNoExports) {
 }
 
 TEST_F(LinkerTest, RunLinkWithPotentialIntrinsicNameCollisions) {
-  LPCWSTR option[] = { L"-Zi", L"-Qembed_debug" };
+  LPCWSTR option[] = { L"-Zi", L"-Qembed_debug", L"-default-linkage", L"external" };
 
   CComPtr<IDxcBlob> pLib1;
   CompileLib(L"..\\CodeGenHLSL\\linker\\createHandle_multi.hlsl",
-    &pLib1, option);
+    &pLib1, option, L"lib_6_3");
   CComPtr<IDxcBlob> pLib2;
   CompileLib(L"..\\CodeGenHLSL\\linker\\createHandle_multi2.hlsl",
-    &pLib2, option);
+    &pLib2, option, L"lib_6_3");
 
   CComPtr<IDxcLinker> pLinker;
   CreateLinker(&pLinker);

+ 1 - 0
utils/hct/hctdb.py

@@ -2136,6 +2136,7 @@ class db_dxil(object):
                 {'n':'from-binding', 'i':'FromBinding', 't':'bool', 'c':1, 'd':'Append binding to name when bound'},
                 {'n':'keep-name', 'i':'KeepName', 't':'bool', 'c':1, 'd':'Keep name when appending binding'},
             ])
+        add_pass('hlsl-dxil-resources-to-handle', 'DxilMutateResourceToHandle', 'Mutate resource to handle',[])
 
         category_lib="llvm"
         add_pass('ipsccp', 'IPSCCP', 'Interprocedural Sparse Conditional Constant Propagation', [])