2
0
Эх сурвалжийг харах

Merged PR 100: Eliminate phi on resources/handles for library

Eliminate phi on resources/handles for library

- ensure all handles use only one global resource
- replace resource path with indices into global resource
- replace resource alloca with index allocas
- AddCreateHandleForPhiNodeAndSelect now unnecessary, deleted
- error on resources in library function params or return
- mark entry clones as internal linkage since they could contain params
  that are not allowed for libraries.
- fix MarkUavUpdateCounter - handle nested GEP
- disallow static resource use from exported library functions
- add/update tests
- detect undef resource paths that would otherwise be lost (FailUndefResource)
- set internal linkage for HL intrinsic function bodies so they aren't processed with user functions
- Rename legalize [static] resource use passes to DxilPromote(Local|Static)Resources
- Remove various dead code paths for resources, such as:
  GenerateParamDxilResourceHandles, RemoveLocalDxilResourceAllocas,
  lower handle cast, non-promotable error (may translate to index allocas)
- force resource GVs to external constant with no initializer
Tex Riddell 7 жил өмнө
parent
commit
734accbce5
41 өөрчлөгдсөн 1478 нэмэгдсэн , 640 устгасан
  1. 8 4
      include/dxc/HLSL/DxilGenerationPass.h
  2. 6 2
      include/dxc/HLSL/DxilUtil.h
  3. 4 2
      lib/HLSL/DxcOptimizer.cpp
  4. 977 121
      lib/HLSL/DxilCondenseResources.cpp
  5. 96 295
      lib/HLSL/DxilGenerationPass.cpp
  6. 44 0
      lib/HLSL/DxilPreparePasses.cpp
  7. 42 14
      lib/HLSL/DxilUtil.cpp
  8. 2 0
      lib/HLSL/HLOperations.cpp
  9. 12 3
      lib/Transforms/IPO/PassManagerBuilder.cpp
  10. 61 2
      tools/clang/lib/CodeGen/CGHLSLMS.cpp
  11. 0 3
      tools/clang/test/CodeGenHLSL/lib_cs_entry.hlsl
  12. 0 4
      tools/clang/test/CodeGenHLSL/lib_cs_entry3.hlsl
  13. 1 11
      tools/clang/test/CodeGenHLSL/lib_entries.hlsl
  14. 0 7
      tools/clang/test/CodeGenHLSL/lib_entries2.hlsl
  15. 2 2
      tools/clang/test/CodeGenHLSL/lib_resource.hlsl
  16. 1 66
      tools/clang/test/CodeGenHLSL/quick-test/d3dreflect/reflect-lib-1.hlsl
  17. 1 0
      tools/clang/test/CodeGenHLSL/quick-test/lib_append_buf.hlsl
  18. 5 6
      tools/clang/test/CodeGenHLSL/quick-test/lib_mat_cast.hlsl
  19. 2 2
      tools/clang/test/CodeGenHLSL/quick-test/lib_mat_entry8.hlsl
  20. 4 2
      tools/clang/test/CodeGenHLSL/quick-test/lib_res_param.hlsl
  21. 3 4
      tools/clang/test/CodeGenHLSL/quick-test/lib_select_res.hlsl
  22. 1 1
      tools/clang/test/CodeGenHLSL/quick-test/local_res_array2.hlsl
  23. 15 0
      tools/clang/test/CodeGenHLSL/quick-test/local_res_array3.hlsl
  24. 1 1
      tools/clang/test/CodeGenHLSL/quick-test/local_res_fail_map_error_msg.hlsl
  25. 42 0
      tools/clang/test/CodeGenHLSL/quick-test/no-phi-on-res.hlsl
  26. 2 2
      tools/clang/test/CodeGenHLSL/quick-test/raytracing_callable.hlsl
  27. 1 1
      tools/clang/test/CodeGenHLSL/quick-test/raytracing_raygeneration.hlsl
  28. 4 2
      tools/clang/test/CodeGenHLSL/quick-test/res_in_struct.hlsl
  29. 21 12
      tools/clang/test/CodeGenHLSL/quick-test/res_select2.hlsl
  30. 11 12
      tools/clang/test/CodeGenHLSL/quick-test/res_select3.hlsl
  31. 35 0
      tools/clang/test/CodeGenHLSL/quick-test/res_select4.hlsl
  32. 33 0
      tools/clang/test/CodeGenHLSL/quick-test/res_select5.hlsl
  33. 2 3
      tools/clang/test/CodeGenHLSL/selectObj4.hlsl
  34. 4 2
      tools/clang/test/CodeGenHLSL/shader-compat-suite/ignore_line_directives.hlsl
  35. 4 2
      tools/clang/test/CodeGenHLSL/shader-compat-suite/lib_out_param_res.hlsl
  36. 4 3
      tools/clang/test/CodeGenHLSL/shader-compat-suite/lib_out_param_res_imp.hlsl
  37. 2 2
      tools/clang/test/CodeGenHLSL/shader-compat-suite/lib_res_sel.hlsl
  38. 5 3
      tools/clang/test/CodeGenHLSL/shader-compat-suite/lib_ret_res.hlsl
  39. 1 30
      tools/clang/unittests/HLSL/DxilContainerTest.cpp
  40. 15 12
      tools/clang/unittests/HLSL/LinkerTest.cpp
  41. 4 2
      utils/hct/hctdb.py

+ 8 - 4
include/dxc/HLSL/DxilGenerationPass.h

@@ -61,10 +61,12 @@ ModulePass *createHLDeadFunctionEliminationPass();
 ModulePass *createHLPreprocessPass();
 ModulePass *createDxilPrecisePropagatePass();
 FunctionPass *createDxilPreserveAllOutputsPass();
-FunctionPass *createDxilLegalizeResourceUsePass();
-ModulePass *createDxilLegalizeStaticResourceUsePass();
+FunctionPass *createDxilPromoteLocalResources();
+ModulePass *createDxilPromoteStaticResources();
+ModulePass *createDxilLegalizeResources();
 ModulePass *createDxilLegalizeEvalOperationsPass();
 FunctionPass *createDxilLegalizeSampleOffsetPass();
+ModulePass *createFailUndefResourcePass();
 FunctionPass *createSimplifyInstPass();
 ModulePass *createDxilTranslateRawBuffer();
 ModulePass *createNoPausePassesPass();
@@ -90,10 +92,12 @@ void initializeDxilConvergentMarkPass(llvm::PassRegistry&);
 void initializeDxilConvergentClearPass(llvm::PassRegistry&);
 void initializeDxilPrecisePropagatePassPass(llvm::PassRegistry&);
 void initializeDxilPreserveAllOutputsPass(llvm::PassRegistry&);
-void initializeDxilLegalizeResourceUsePassPass(llvm::PassRegistry&);
-void initializeDxilLegalizeStaticResourceUsePassPass(llvm::PassRegistry&);
+void initializeDxilPromoteLocalResourcesPass(llvm::PassRegistry&);
+void initializeDxilPromoteStaticResourcesPass(llvm::PassRegistry&);
+void initializeDxilLegalizeResourcesPass(llvm::PassRegistry&);
 void initializeDxilLegalizeEvalOperationsPass(llvm::PassRegistry&);
 void initializeDxilLegalizeSampleOffsetPassPass(llvm::PassRegistry&);
+void initializeFailUndefResourcePass(llvm::PassRegistry&);
 void initializeSimplifyInstPass(llvm::PassRegistry&);
 void initializeDxilTranslateRawBufferPass(llvm::PassRegistry&);
 void initializeNoPausePassesPass(llvm::PassRegistry&);

+ 6 - 2
include/dxc/HLSL/DxilUtil.h

@@ -37,6 +37,7 @@ class DxilTypeSystem;
 namespace dxilutil {
   extern const char ManglingPrefix[];
   extern const char EntryPrefix[];
+  extern const llvm::StringRef kResourceMapErrorMsg;
 
   unsigned
   GetLegacyCBufferFieldElementSize(DxilFieldAnnotation &fieldAnnotation,
@@ -57,6 +58,7 @@ namespace dxilutil {
   bool IsSharedMemoryGlobal(llvm::GlobalVariable *GV);
   bool RemoveUnusedFunctions(llvm::Module &M, llvm::Function *EntryFunc,
                              llvm::Function *PatchConstantFunc, bool IsLib);
+  void EmitErrorOnInstruction(llvm::Instruction *I, llvm::StringRef Msg);
   void EmitResMappingError(llvm::Instruction *Res);
   // Simple demangle just support case "\01?name@" pattern.
   llvm::StringRef DemangleFunctionName(llvm::StringRef name);
@@ -79,8 +81,10 @@ namespace dxilutil {
   void CollectSelect(llvm::Instruction *Inst,
                    std::unordered_set<llvm::Instruction *> &selectSet);
   // If all operands are the same for a select inst, replace it with the operand.
-  bool MergeSelectOnSameValue(llvm::Instruction *SelInst, unsigned startOpIdx,
-                            unsigned numOperands);
+  // Returns replacement value if successful
+  llvm::Value *MergeSelectOnSameValue(llvm::Instruction *SelInst,
+                                      unsigned startOpIdx,
+                                      unsigned numOperands);
   std::unique_ptr<llvm::Module> LoadModuleFromBitcode(llvm::StringRef BC,
     llvm::LLVMContext &Ctx, std::string &DiagStr);
   std::unique_ptr<llvm::Module> LoadModuleFromBitcode(llvm::MemoryBuffer *MB,

+ 4 - 2
lib/HLSL/DxcOptimizer.cpp

@@ -99,14 +99,15 @@ HRESULT SetupRegistryPassForHLSL() {
     initializeDxilForceEarlyZPass(Registry);
     initializeDxilGenerationPassPass(Registry);
     initializeDxilLegalizeEvalOperationsPass(Registry);
-    initializeDxilLegalizeResourceUsePassPass(Registry);
+    initializeDxilLegalizeResourcesPass(Registry);
     initializeDxilLegalizeSampleOffsetPassPass(Registry);
-    initializeDxilLegalizeStaticResourceUsePassPass(Registry);
     initializeDxilLoadMetadataPass(Registry);
     initializeDxilLowerCreateHandleForLibPass(Registry);
     initializeDxilOutputColorBecomesConstantPass(Registry);
     initializeDxilPrecisePropagatePassPass(Registry);
     initializeDxilPreserveAllOutputsPass(Registry);
+    initializeDxilPromoteLocalResourcesPass(Registry);
+    initializeDxilPromoteStaticResourcesPass(Registry);
     initializeDxilReduceMSAAToSingleSamplePass(Registry);
     initializeDxilRemoveDiscardsPass(Registry);
     initializeDxilShaderAccessTrackingPass(Registry);
@@ -114,6 +115,7 @@ HRESULT SetupRegistryPassForHLSL() {
     initializeDynamicIndexingVectorToArrayPass(Registry);
     initializeEarlyCSELegacyPassPass(Registry);
     initializeEliminateAvailableExternallyPass(Registry);
+    initializeFailUndefResourcePass(Registry);
     initializeFloat2IntPass(Registry);
     initializeFunctionAttrsPass(Registry);
     initializeGVNPass(Registry);

Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 977 - 121
lib/HLSL/DxilCondenseResources.cpp


+ 96 - 295
lib/HLSL/DxilGenerationPass.cpp

@@ -14,6 +14,7 @@
 #include "dxc/HLSL/DxilModule.h"
 #include "dxc/HLSL/HLModule.h"
 #include "dxc/HLSL/HLOperations.h"
+#include "dxc/HLSL/DxilInstructions.h"
 #include "dxc/HLSL/HLMatrixLowerHelper.h"
 #include "dxc/HlslIntrinsicOp.h"
 #include "dxc/Support/Global.h"
@@ -33,6 +34,7 @@
 #include "llvm/IR/DebugInfo.h"
 #include "llvm/IR/PassManager.h"
 #include "llvm/ADT/BitVector.h"
+#include "llvm/ADT/SetVector.h"
 #include "llvm/Pass.h"
 #include "llvm/Transforms/Utils/SSAUpdater.h"
 #include "llvm/Analysis/AssumptionCache.h"
@@ -283,21 +285,17 @@ public:
     LowerHLCreateHandle();
     MarkNonUniform(NonUniformSet);
 
-    // For module which not promote mem2reg.
-    // Remove local resource alloca/load/store/phi.
-    // Skip lib in case alloca used as call arg.
-    if (!SM->IsLib()) {
-      for (auto It = M.begin(); It != M.end();) {
-        Function &F = *(It++);
-        if (!F.isDeclaration()) {
-          RemoveLocalDxilResourceAllocas(&F);
-          if (hlsl::GetHLOpcodeGroupByName(&F) ==
-              HLOpcodeGroup::HLCreateHandle) {
-            if (F.user_empty()) {
-              F.eraseFromParent();
-            } else {
-              M.getContext().emitError("Fail to lower createHandle.");
-            }
+    // LowerHLCreateHandle() should have translated HLCreateHandle to CreateHandleForLib.
+    // Clean up HLCreateHandle functions.
+    for (auto It = M.begin(); It != M.end();) {
+      Function &F = *(It++);
+      if (!F.isDeclaration()) {
+        if (hlsl::GetHLOpcodeGroupByName(&F) ==
+            HLOpcodeGroup::HLCreateHandle) {
+          if (F.user_empty()) {
+            F.eraseFromParent();
+          } else {
+            M.getContext().emitError("Fail to lower createHandle.");
           }
         }
       }
@@ -328,11 +326,7 @@ public:
   }
 
 private:
-  void RemoveLocalDxilResourceAllocas(Function *F);
   void MarkUpdateCounter(std::unordered_set<LoadInst *> &UpdateCounterSet);
-  void TranslateParamDxilResourceHandles(Function *F, std::unordered_map<Instruction *, Value *> &handleMap);
-  void GenerateParamDxilResourceHandles(
-      std::unordered_map<Instruction *, Value *> &handleMap);
   // Generate DXIL cbuffer handles.
   void
   GenerateDxilCBufferHandles(std::unordered_set<Value *> &NonUniformSet);
@@ -411,149 +405,25 @@ void DxilGenerationPass::MarkNonUniform(
   }
 }
 
-static const StringRef kResourceMapErrorMsg = "local resource not guaranteed to map to unique global resource.";
-static void EmitResMappingError(Instruction *Res) {
-  const DebugLoc &DL = Res->getDebugLoc();
-  if (DL.get()) {
-    Res->getContext().emitError("line:" + std::to_string(DL.getLine()) +
-        " col:" + std::to_string(DL.getCol()) + " " +
-        Twine(kResourceMapErrorMsg));
-  } else {
-    Res->getContext().emitError(Twine(kResourceMapErrorMsg) + " With /Zi to show more information.");
-  }
-}
-
-static void ReplaceResourceUserWithHandle(LoadInst *Res, Value *handle) {
-  for (auto resUser = Res->user_begin(); resUser != Res->user_end();) {
-    CallInst *CI = dyn_cast<CallInst>(*(resUser++));
-    DXASSERT(GetHLOpcodeGroupByName(CI->getCalledFunction()) ==
-                 HLOpcodeGroup::HLCreateHandle,
-             "must be createHandle");
-    CI->replaceAllUsesWith(handle);
-    CI->eraseFromParent();
-  }
-  Res->eraseFromParent();
-}
-
-static bool IsResourceType(Type *Ty) {
-  bool isResource = HLModule::IsHLSLObjectType(Ty);
-
-  if (ArrayType *AT = dyn_cast<ArrayType>(Ty)) {
-    Type *EltTy = AT->getElementType();
-    while (isa<ArrayType>(EltTy)) {
-      EltTy = EltTy->getArrayElementType();
-    }
-    isResource = HLModule::IsHLSLObjectType(EltTy);
-    // TODO: support local resource array.
-    DXASSERT(!isResource, "local resource array");
-  }
-  return isResource;
-}
-
-void DxilGenerationPass::RemoveLocalDxilResourceAllocas(Function *F) {
-  BasicBlock &BB = F->getEntryBlock(); // Get the entry node for the function
-  std::unordered_set<AllocaInst *> localResources;
-  for (BasicBlock::iterator I = BB.begin(), E = --BB.end(); I != E; ++I)
-    if (AllocaInst *AI = dyn_cast<AllocaInst>(I)) { // Is it an alloca?
-      if (IsResourceType(AI->getAllocatedType())) {
-        localResources.insert(AI);
-      }
-    }
-
-  SSAUpdater SSA;
-  SmallVector<Instruction *, 4> Insts;
-
-  for (AllocaInst *AI : localResources) {
-    // Build list of instructions to promote.
-    for (User *U : AI->users())
-      Insts.emplace_back(cast<Instruction>(U));
-
-    ResourceRemover(Insts, SSA).run(AI, Insts);
-
-    Insts.clear();
-  }
-}
-void DxilGenerationPass::TranslateParamDxilResourceHandles(Function *F, std::unordered_map<Instruction *, Value *> &handleMap) {
-  Type *handleTy = m_pHLModule->GetOP()->GetHandleType();
-
-  IRBuilder<> Builder(dxilutil::FirstNonAllocaInsertionPt(F));
-  for (Argument &arg : F->args()) {
-    Type *Ty = arg.getType();
-
-    if (isa<PointerType>(Ty))
-      Ty = Ty->getPointerElementType();
-
-    SmallVector<unsigned,4> arraySizeList;
-    while (isa<ArrayType>(Ty)) {
-      arraySizeList.push_back(Ty->getArrayNumElements());
-      Ty = Ty->getArrayElementType();
+static void
+MarkUavUpdateCounter(Value* LoadOrGEP,
+                     DxilResource &res,
+                     std::unordered_set<LoadInst *> &UpdateCounterSet) {
+  if (LoadInst *ldInst = dyn_cast<LoadInst>(LoadOrGEP)) {
+    if (UpdateCounterSet.count(ldInst)) {
+      DXASSERT_NOMSG(res.GetClass() == DXIL::ResourceClass::UAV);
+      res.SetHasCounter(true);
     }
-    DXIL::ResourceClass RC = m_pHLModule->GetResourceClass(Ty);
-    if (RC != DXIL::ResourceClass::Invalid) {
-      Type *curTy = handleTy;
-      for (auto it = arraySizeList.rbegin(), E = arraySizeList.rend(); it != E;
-           it++) {
-        curTy = ArrayType::get(curTy, *it);
-      }
-      curTy = PointerType::get(curTy, 0);
-      CallInst *castToHandle = cast<CallInst>(HLModule::EmitHLOperationCall(
-          Builder, HLOpcodeGroup::HLCast, 0, curTy,
-          {UndefValue::get(arg.getType())}, *F->getParent()));
-
-      for (User *U : arg.users()) {
-        Instruction *I = cast<Instruction>(U);
-        IRBuilder<> userBuilder(I);
-        if (LoadInst *ldInst = dyn_cast<LoadInst>(U)) {
-          Value *handleLd = userBuilder.CreateLoad(castToHandle);
-          handleMap[ldInst] = handleLd;
-        } else if (StoreInst *stInst = dyn_cast<StoreInst>(U)) {
-          Value *res = stInst->getValueOperand();
-          Value *handle = HLModule::EmitHLOperationCall(
-              userBuilder, HLOpcodeGroup::HLCast, 0, handleTy, {res},
-              *F->getParent());
-          userBuilder.CreateStore(handle, castToHandle);
-        } else if (dyn_cast<CallInst>(U)) {
-          // Don't flatten argument here.
-          continue;
-        } else {
-          DXASSERT(
-              dyn_cast<GEPOperator>(U) != nullptr,
-              "else AddOpcodeParamForIntrinsic in CodeGen did not patch uses "
-              "to only have ld/st refer to temp object");
-          GEPOperator *GEP = cast<GEPOperator>(U);
-          std::vector<Value *> idxList(GEP->idx_begin(), GEP->idx_end());
-          Value *handleGEP = userBuilder.CreateGEP(castToHandle, idxList);
-          for (auto GEPU : GEP->users()) {
-            Instruction *GEPI = cast<Instruction>(GEPU);
-            IRBuilder<> gepUserBuilder(GEPI);
-            if (LoadInst *ldInst = dyn_cast<LoadInst>(GEPU)) {
-              handleMap[ldInst] = gepUserBuilder.CreateLoad(handleGEP);
-            } else {
-              StoreInst *stInst = cast<StoreInst>(GEPU);
-              Value *res = stInst->getValueOperand();
-              Value *handle = HLModule::EmitHLOperationCall(
-                  gepUserBuilder, HLOpcodeGroup::HLCast, 0, handleTy, {res},
-                  *F->getParent());
-              gepUserBuilder.CreateStore(handle, handleGEP);
-            }
-          }
-        }
-      }
-
-      castToHandle->setArgOperand(0, &arg);
+  } else {
+    DXASSERT(dyn_cast<GEPOperator>(LoadOrGEP) != nullptr,
+             "else AddOpcodeParamForIntrinsic in CodeGen did not patch uses "
+             "to only have ld/st refer to temp object");
+    GEPOperator *GEP = cast<GEPOperator>(LoadOrGEP);
+    for (auto GEPU : GEP->users()) {
+      MarkUavUpdateCounter(GEPU, res, UpdateCounterSet);
     }
   }
 }
-
-void DxilGenerationPass::GenerateParamDxilResourceHandles(
-    std::unordered_map<Instruction *, Value *> &handleMap) {
-  Module &M = *m_pHLModule->GetModule();
-  for (Function &F : M.functions()) {
-    if (!F.isDeclaration())
-      TranslateParamDxilResourceHandles(&F, handleMap);
-  }
-}
-
 static void
 MarkUavUpdateCounter(DxilResource &res,
                      std::unordered_set<LoadInst *> &UpdateCounterSet) {
@@ -563,27 +433,7 @@ MarkUavUpdateCounter(DxilResource &res,
     // Skip unused user.
     if (user->user_empty())
       continue;
-
-    if (LoadInst *ldInst = dyn_cast<LoadInst>(user)) {
-      if (UpdateCounterSet.count(ldInst)) {
-        DXASSERT_NOMSG(res.GetClass() == DXIL::ResourceClass::UAV);
-        res.SetHasCounter(true);
-      }
-    } else {
-      DXASSERT(dyn_cast<GEPOperator>(user) != nullptr,
-               "else AddOpcodeParamForIntrinsic in CodeGen did not patch uses "
-               "to only have ld/st refer to temp object");
-      GEPOperator *GEP = cast<GEPOperator>(user);
-      for (auto GEPU = GEP->user_begin(), GEPE = GEP->user_end();
-           GEPU != GEPE;) {
-        // Must be load inst.
-        LoadInst *ldInst = cast<LoadInst>(*(GEPU++));
-        if (UpdateCounterSet.count(ldInst)) {
-          DXASSERT_NOMSG(res.GetClass() == DXIL::ResourceClass::UAV);
-          res.SetHasCounter(true);
-        }
-      }
-    }
+    MarkUavUpdateCounter(user, res, UpdateCounterSet);
   }
 }
 
@@ -1042,10 +892,12 @@ INITIALIZE_PASS(HLDeadFunctionElimination, "hl-dfe", "Remove all unused function
 
 namespace {
 
-class DxilLegalizeStaticResourceUsePass : public ModulePass {
+static const StringRef kStaticResourceLibErrorMsg = "static global resource use is disallowed in library exports.";
+
+class DxilPromoteStaticResources : public ModulePass {
 public:
   static char ID; // Pass identification, replacement for typeid
-  explicit DxilLegalizeStaticResourceUsePass()
+  explicit DxilPromoteStaticResources()
       : ModulePass(ID) {}
 
   const char *getPassName() const override {
@@ -1053,55 +905,22 @@ public:
   }
 
   bool runOnModule(Module &M) override {
-    HLModule &HLM = M.GetOrCreateHLModule();
-    OP *hlslOP = HLM.GetOP();
-    Type *HandleTy = hlslOP->GetHandleType();
     // Promote static global variables.
-    PromoteStaticGlobalResources(M);
-
-    // Lower handle cast.
-    for (Function &F : M.functions()) {
-      if (!F.isDeclaration())
-        continue;
-      HLOpcodeGroup group = hlsl::GetHLOpcodeGroupByName(&F);
-      if (group != HLOpcodeGroup::HLCast)
-        continue;
-      Type *Ty = F.getFunctionType()->getReturnType();
-      if (Ty->isPointerTy())
-        Ty = Ty->getPointerElementType();
-      if (HLModule::IsHLSLObjectType(Ty)) {
-        TransformHandleCast(F);
-      }
-    }
-
-    Value *UndefHandle = UndefValue::get(HandleTy);
-    if (!UndefHandle->user_empty()) {
-      for (User *U : UndefHandle->users()) {
-        // Report error if undef handle used for function call.
-        if (isa<CallInst>(U)) {
-          if (Instruction *UI = dyn_cast<Instruction>(U))
-            EmitResMappingError(UI);
-          else
-            M.getContext().emitError(kResourceMapErrorMsg);
-        }
-      }
-    }
-    return true;
+    return PromoteStaticGlobalResources(M);
   }
 
 private:
-  void PromoteStaticGlobalResources(Module &M);
-  void TransformHandleCast(Function &F);
+  bool PromoteStaticGlobalResources(Module &M);
 };
 
-char DxilLegalizeStaticResourceUsePass::ID = 0;
+char DxilPromoteStaticResources::ID = 0;
 
-class DxilLegalizeResourceUsePass : public FunctionPass {
+class DxilPromoteLocalResources : public FunctionPass {
   void getAnalysisUsage(AnalysisUsage &AU) const override;
 
 public:
   static char ID; // Pass identification, replacement for typeid
-  explicit DxilLegalizeResourceUsePass()
+  explicit DxilPromoteLocalResources()
       : FunctionPass(ID) {}
 
   const char *getPassName() const override {
@@ -1110,34 +929,29 @@ public:
 
   bool runOnFunction(Function &F) override {
     // Promote local resource first.
-    PromoteLocalResource(F);
-    return true;
+    return PromoteLocalResource(F);
   }
 
 private:
-  void PromoteLocalResource(Function &F);
+  bool PromoteLocalResource(Function &F);
 };
 
-char DxilLegalizeResourceUsePass::ID = 0;
+char DxilPromoteLocalResources::ID = 0;
 
 }
 
-void DxilLegalizeResourceUsePass::getAnalysisUsage(AnalysisUsage &AU) const {
+void DxilPromoteLocalResources::getAnalysisUsage(AnalysisUsage &AU) const {
   AU.addRequired<AssumptionCacheTracker>();
   AU.addRequired<DominatorTreeWrapperPass>();
   AU.setPreservesAll();
 }
 
-void DxilLegalizeResourceUsePass::PromoteLocalResource(Function &F) {
+bool DxilPromoteLocalResources::PromoteLocalResource(Function &F) {
+  bool bModified = false;
   std::vector<AllocaInst *> Allocas;
   DominatorTree *DT = &getAnalysis<DominatorTreeWrapperPass>().getDomTree();
   AssumptionCache &AC =
       getAnalysis<AssumptionCacheTracker>().getAssumptionCache(F);
-  HLModule &HLM = F.getParent()->GetOrCreateHLModule();
-  OP *hlslOP = HLM.GetOP();
-  Type *HandleTy = hlslOP->GetHandleType();
-
-  bool IsLib = HLM.GetShaderModel()->IsLib();
 
   BasicBlock &BB = F.getEntryBlock();
   unsigned allocaSize = 0;
@@ -1148,19 +962,9 @@ void DxilLegalizeResourceUsePass::PromoteLocalResource(Function &F) {
     // the entry node
     for (BasicBlock::iterator I = BB.begin(), E = --BB.end(); I != E; ++I)
       if (AllocaInst *AI = dyn_cast<AllocaInst>(I)) { // Is it an alloca?
-        if (HandleTy == dxilutil::GetArrayEltTy(AI->getAllocatedType())) {
-          // Skip for unpromotable for lib.
-          if (!isAllocaPromotable(AI) && IsLib)
-            continue;
-          if (!isAllocaPromotable(AI)) {
-            static const StringRef kNonPromotableLocalResourceErrorMsg =
-                "non-promotable local resource found.";
-            F.getContext().emitError(kNonPromotableLocalResourceErrorMsg);
-            throw hlsl::Exception(DXC_E_ABORT_COMPILATION_ERROR,
-                                  kNonPromotableLocalResourceErrorMsg);
-            continue;
-          }
-          Allocas.push_back(AI);
+        if (HLModule::IsHLSLObjectType(dxilutil::GetArrayEltTy(AI->getAllocatedType()))) {
+          if (isAllocaPromotable(AI))
+            Allocas.push_back(AI);
         }
       }
     if (Allocas.empty())
@@ -1169,39 +973,65 @@ void DxilLegalizeResourceUsePass::PromoteLocalResource(Function &F) {
     // No update.
     // Report error and break.
     if (allocaSize == Allocas.size()) {
-      F.getContext().emitError(kResourceMapErrorMsg);
+      F.getContext().emitError(dxilutil::kResourceMapErrorMsg);
       break;
     }
     allocaSize = Allocas.size();
 
     PromoteMemToReg(Allocas, *DT, nullptr, &AC);
+    bModified = true;
   }
 
-  return;
+  return bModified;
 }
 
-FunctionPass *llvm::createDxilLegalizeResourceUsePass() {
-  return new DxilLegalizeResourceUsePass();
+FunctionPass *llvm::createDxilPromoteLocalResources() {
+  return new DxilPromoteLocalResources();
 }
 
-INITIALIZE_PASS_BEGIN(DxilLegalizeResourceUsePass,
-                      "hlsl-dxil-legalize-resource-use",
-                      "DXIL legalize resource use", false, true)
+INITIALIZE_PASS_BEGIN(DxilPromoteLocalResources,
+                      "hlsl-dxil-promote-local-resources",
+                      "DXIL promote local resource use", false, true)
 INITIALIZE_PASS_DEPENDENCY(AssumptionCacheTracker)
 INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)
-INITIALIZE_PASS_END(DxilLegalizeResourceUsePass,
-                    "hlsl-dxil-legalize-resource-use",
-                    "DXIL legalize resource use", false, true)
+INITIALIZE_PASS_END(DxilPromoteLocalResources,
+                    "hlsl-dxil-promote-local-resources",
+                    "DXIL promote local resource use", false, true)
 
-void DxilLegalizeStaticResourceUsePass::PromoteStaticGlobalResources(
+bool DxilPromoteStaticResources::PromoteStaticGlobalResources(
     Module &M) {
-  HLModule &HLM = M.GetOrCreateHLModule();
-  Type *HandleTy = HLM.GetOP()->GetHandleType();
+  if (M.GetOrCreateHLModule().GetShaderModel()->IsLib()) {
+    // Read/write to global static resource is disallowed for libraries:
+    // Resource use needs to be resolved to a single real global resource,
+    // but it may not be possible since any external function call may re-enter
+    // at any other library export, which could modify the global static
+    // between write and read.
+    // While it could work for certain cases, describing the boundary at
+    // the HLSL level is difficult, so at this point it's better to disallow.
+    // example of what could work:
+    //  After inlining, exported functions must have writes to static globals
+    //  before reads, and must not have any external function calls between
+    //  writes and subsequent reads, such that the static global may be
+    //  optimized away for the exported function.
+    for (auto &GV : M.globals()) {
+      if (GV.getLinkage() == GlobalVariable::LinkageTypes::InternalLinkage &&
+        HLModule::IsHLSLObjectType(dxilutil::GetArrayEltTy(GV.getType()))) {
+        if (!GV.user_empty()) {
+          if (Instruction *I = dyn_cast<Instruction>(*GV.user_begin())) {
+            dxilutil::EmitErrorOnInstruction(I, kStaticResourceLibErrorMsg);
+            break;
+          }
+        }
+      }
+    }
+    return false;
+  }
 
+  bool bModified = false;
   std::set<GlobalVariable *> staticResources;
   for (auto &GV : M.globals()) {
-    if (GV.getLinkage() == GlobalValue::LinkageTypes::InternalLinkage &&
-        HandleTy == dxilutil::GetArrayEltTy(GV.getType())) {
+    if (GV.getLinkage() == GlobalVariable::LinkageTypes::InternalLinkage &&
+        HLModule::IsHLSLObjectType(dxilutil::GetArrayEltTy(GV.getType()))) {
       staticResources.insert(&GV);
     }
   }
@@ -1227,50 +1057,21 @@ void DxilLegalizeStaticResourceUsePass::PromoteStaticGlobalResources(
       Insts.clear();
     }
     if (!bUpdated) {
-      M.getContext().emitError(kResourceMapErrorMsg);
+      M.getContext().emitError(dxilutil::kResourceMapErrorMsg);
       break;
     }
+    bModified = true;
   }
+  return bModified;
 }
 
-static void ReplaceResUseWithHandle(Instruction *Res, Value *Handle) {
-  Type *HandleTy = Handle->getType();
-  for (auto ResU = Res->user_begin(); ResU != Res->user_end();) {
-    Instruction *I = cast<Instruction>(*(ResU++));
-    if (isa<LoadInst>(I)) {
-      ReplaceResUseWithHandle(I, Handle);
-    } else if (isa<CallInst>(I)) {
-      if (I->getType() == HandleTy) {
-        I->replaceAllUsesWith(Handle);
-      } else {
-        DXASSERT(0, "must createHandle here");
-      }
-    } else {
-      DXASSERT(0, "should only used by load and createHandle");
-    }
-    if (I->user_empty() && !I->getType()->isVoidTy()) {
-      I->eraseFromParent();
-    }
-  }
-}
-
-void DxilLegalizeStaticResourceUsePass::TransformHandleCast(Function &F) {
-  for (auto U = F.user_begin(); U != F.user_end(); ) {
-    CallInst *CI = cast<CallInst>(*(U++));
-    Value *Handle = CI->getArgOperand(HLOperandIndex::kUnaryOpSrc0Idx);
-    ReplaceResUseWithHandle(CI, Handle);
-    if (CI->user_empty())
-      CI->eraseFromParent();
-  }
-}
-
-ModulePass *llvm::createDxilLegalizeStaticResourceUsePass() {
-  return new DxilLegalizeStaticResourceUsePass();
+ModulePass *llvm::createDxilPromoteStaticResources() {
+  return new DxilPromoteStaticResources();
 }
 
-INITIALIZE_PASS(DxilLegalizeStaticResourceUsePass,
-                "hlsl-dxil-legalize-static-resource-use",
-                "DXIL legalize static resource use", false, false)
+INITIALIZE_PASS(DxilPromoteStaticResources,
+                "hlsl-dxil-promote-static-resources",
+                "DXIL promote static resource use", false, false)
 
 ///////////////////////////////////////////////////////////////////////////////
 // Legalize EvalOperations.

+ 44 - 0
lib/HLSL/DxilPreparePasses.cpp

@@ -11,6 +11,7 @@
 
 #include "dxc/HLSL/DxilGenerationPass.h"
 #include "dxc/HLSL/DxilOperations.h"
+#include "dxc/HLSL/HLOperations.h"
 #include "dxc/HLSL/DxilModule.h"
 #include "dxc/Support/Global.h"
 #include "dxc/HLSL/DxilTypeSystem.h"
@@ -34,6 +35,49 @@
 using namespace llvm;
 using namespace hlsl;
 
+namespace {
+class FailUndefResource : public ModulePass {
+public:
+  static char ID;
+
+  explicit FailUndefResource() : ModulePass(ID) {
+    initializeScalarizerPass(*PassRegistry::getPassRegistry());
+  }
+
+  const char *getPassName() const override { return "Fail on undef resource use"; }
+
+  bool runOnModule(Module &M) override;
+};
+}
+
+char FailUndefResource::ID = 0;
+
+ModulePass *llvm::createFailUndefResourcePass() { return new FailUndefResource(); }
+
+INITIALIZE_PASS(FailUndefResource, "fail-undef-resource", "Fail on undef resource use", false, false)
+
+bool FailUndefResource::runOnModule(Module &M) {
+  // Undef resources may be removed on simplify due to the interpretation
+  // of undef that any value could be substituted for identical meaning.
+  // However, these likely indicate uninitialized locals being used in
+  // some code path, which we should catch and report.
+  for (auto &F : M.functions()) {
+    if (GetHLOpcodeGroupByName(&F) == HLOpcodeGroup::HLCreateHandle) {
+      Type *ResTy = F.getFunctionType()->getParamType(
+        HLOperandIndex::kCreateHandleResourceOpIdx);
+      UndefValue *UndefRes = UndefValue::get(ResTy);
+      for (auto U : UndefRes->users()) {
+        // Only report instruction users.
+        if (Instruction *I = dyn_cast<Instruction>(U))
+          dxilutil::EmitResMappingError(I);
+      }
+    }
+  }
+  return false;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
 namespace {
 class SimplifyInst : public FunctionPass {
 public:

+ 42 - 14
lib/HLSL/DxilUtil.cpp

@@ -213,18 +213,47 @@ std::unique_ptr<llvm::Module> LoadModuleFromBitcode(llvm::StringRef BC,
   return LoadModuleFromBitcode(pBitcodeBuf.get(), Ctx, DiagStr);
 }
 
-static const StringRef kResourceMapErrorMsg =
-    "local resource not guaranteed to map to unique global resource.";
-void EmitResMappingError(Instruction *Res) {
-  const DebugLoc &DL = Res->getDebugLoc();
+// If we don't have debug location and this is select/phi,
+// try recursing users to find instruction with debug info.
+// Only recurse phi/select and limit depth to prevent doing
+// too much work if no debug location found.
+static bool EmitErrorOnInstructionFollowPhiSelect(
+    Instruction *I, StringRef Msg, unsigned depth=0) {
+  if (depth > 4)
+    return false;
+  if (I->getDebugLoc().get()) {
+    EmitErrorOnInstruction(I, Msg);
+    return true;
+  }
+  if (isa<PHINode>(I) || isa<SelectInst>(I)) {
+    for (auto U : I->users())
+      if (Instruction *UI = dyn_cast<Instruction>(U))
+        if (EmitErrorOnInstructionFollowPhiSelect(UI, Msg, depth+1))
+          return true;
+  }
+  return false;
+}
+
+void EmitErrorOnInstruction(Instruction *I, StringRef Msg) {
+  const DebugLoc &DL = I->getDebugLoc();
   if (DL.get()) {
-    Res->getContext().emitError("line:" + std::to_string(DL.getLine()) +
-                                " col:" + std::to_string(DL.getCol()) + " " +
-                                Twine(kResourceMapErrorMsg));
-  } else {
-    Res->getContext().emitError(Twine(kResourceMapErrorMsg) +
-                                " With /Zi to show more information.");
+    std::string locString;
+    raw_string_ostream os(locString);
+    DL.print(os);
+    I->getContext().emitError(os.str() + ": " + Twine(Msg));
+    return;
+  } else if (isa<PHINode>(I) || isa<SelectInst>(I)) {
+    if (EmitErrorOnInstructionFollowPhiSelect(I, Msg))
+      return;
   }
+
+  I->getContext().emitError(Twine(Msg) + " Use /Zi for source location.");
+}
+
+const StringRef kResourceMapErrorMsg =
+    "local resource not guaranteed to map to unique global resource.";
+void EmitResMappingError(Instruction *Res) {
+  EmitErrorOnInstruction(Res, kResourceMapErrorMsg);
 }
 
 void CollectSelect(llvm::Instruction *Inst,
@@ -253,7 +282,7 @@ void CollectSelect(llvm::Instruction *Inst,
   }
 }
 
-bool MergeSelectOnSameValue(Instruction *SelInst, unsigned startOpIdx,
+Value *MergeSelectOnSameValue(Instruction *SelInst, unsigned startOpIdx,
                             unsigned numOperands) {
   Value *op0 = nullptr;
   for (unsigned i = startOpIdx; i < numOperands; i++) {
@@ -262,15 +291,14 @@ bool MergeSelectOnSameValue(Instruction *SelInst, unsigned startOpIdx,
       op0 = op;
     } else {
       if (op0 != op)
-        return false;
+        return nullptr;
     }
   }
   if (op0) {
     SelInst->replaceAllUsesWith(op0);
     SelInst->eraseFromParent();
-    return true;
   }
-  return false;
+  return op0;
 }
 
 Value *SelectOnOperation(llvm::Instruction *Inst, unsigned operandIdx) {

+ 2 - 0
lib/HLSL/HLOperations.cpp

@@ -493,6 +493,8 @@ Function *GetOrCreateHLFunctionWithBody(Module &M, FunctionType *funcTy,
 
   SetHLFunctionAttribute(F, group, opcode);
 
+  F->setLinkage(llvm::GlobalValue::LinkageTypes::InternalLinkage);
+
   return F;
 }
 

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

@@ -227,7 +227,6 @@ static void addHLSLPasses(bool HLSLHighLevel, unsigned OptLevel, hlsl::HLSLExten
                                              /*Promote*/ !NoOpt));
 
   MPM.add(createHLMatrixLowerPass());
-  MPM.add(createResourceToHandlePass());
   // DCE should after SROA to remove unused element.
   MPM.add(createDeadCodeEliminationPass());
   MPM.add(createGlobalDCEPass());
@@ -253,14 +252,24 @@ static void addHLSLPasses(bool HLSLHighLevel, unsigned OptLevel, hlsl::HLSLExten
     MPM.add(createLoopRotatePass());
     MPM.add(createLoopUnrollPass());
   }
+
+  if (!NoOpt) {
+    // Verify no undef resource path before simplify, since that can remove undef
+    // paths.  For NoOpt, resources are unpromoted here, so this will not work.
+    MPM.add(createFailUndefResourcePass());
+  }
   MPM.add(createSimplifyInstPass());
 
   MPM.add(createCFGSimplificationPass());
 
-  MPM.add(createDxilLegalizeResourceUsePass());
-  MPM.add(createDxilLegalizeStaticResourceUsePass());
+  MPM.add(createDxilPromoteLocalResources());
+  MPM.add(createDxilPromoteStaticResources());
+  // Verify no undef resource again after promotion
+  MPM.add(createFailUndefResourcePass());
+
   MPM.add(createDxilGenerationPass(NoOpt, ExtHelper));
   MPM.add(createDxilLoadMetadataPass()); // Ensure DxilModule is loaded for optimizations.
+
   // Propagate precise attribute.
   MPM.add(createDxilPrecisePropagatePass());
 

+ 61 - 2
tools/clang/lib/CodeGen/CGHLSLMS.cpp

@@ -2214,11 +2214,12 @@ hlsl::DxilResourceBase::Class CGMSHLSLRuntime::TypeToClass(clang::QualType Ty) {
 }
 
 uint32_t CGMSHLSLRuntime::AddSampler(VarDecl *samplerDecl) {
-  llvm::Constant *val = CGM.GetAddrOfGlobalVar(samplerDecl);
+  llvm::GlobalVariable *val =
+    cast<llvm::GlobalVariable>(CGM.GetAddrOfGlobalVar(samplerDecl));
 
   unique_ptr<DxilSampler> hlslRes(new DxilSampler);
   hlslRes->SetLowerBound(UINT_MAX);
-  hlslRes->SetGlobalSymbol(cast<llvm::GlobalVariable>(val));
+  hlslRes->SetGlobalSymbol(val);
   hlslRes->SetGlobalName(samplerDecl->getName());
   QualType VarTy = samplerDecl->getType();
   if (const clang::ArrayType *arrayType =
@@ -4123,6 +4124,7 @@ static void CloneShaderEntry(Function *ShaderF, StringRef EntryName,
                               HLM.GetTypeSystem(), HLM.GetTypeSystem());
 
   F->takeName(ShaderF);
+  F->setLinkage(GlobalValue::LinkageTypes::InternalLinkage);
   // Set to name before mangled.
   ShaderF->setName(EntryName);
 
@@ -4394,6 +4396,39 @@ void CGMSHLSLRuntime::SetPatchConstantFunctionWithAttr(
   
 }
 
+static bool ContainsDisallowedTypeForExport(llvm::Type *Ty) {
+  // Unwrap pointer/array
+  while (llvm::isa<llvm::PointerType>(Ty))
+    Ty = llvm::cast<llvm::PointerType>(Ty)->getPointerElementType();
+  while (llvm::isa<llvm::ArrayType>(Ty))
+    Ty = llvm::cast<llvm::ArrayType>(Ty)->getArrayElementType();
+
+  if (llvm::StructType *ST = llvm::dyn_cast<llvm::StructType>(Ty)) {
+    if (ST->getName().startswith("dx.types."))
+      return true;
+    // TODO: How is this suppoed to check for Input/OutputPatch types if
+    // these have already been eliminated in function arguments during CG?
+    if (HLModule::IsHLSLObjectType(Ty))
+      return true;
+    // Otherwise, recurse elements of UDT
+    for (auto ETy : ST->elements()) {
+      if (ContainsDisallowedTypeForExport(ETy))
+        return true;
+    }
+  }
+  return false;
+}
+
+static void ReportDisallowedTypeInExportParam(CodeGenModule &CGM, StringRef name) {
+  DiagnosticsEngine &Diags = CGM.getDiags();
+  unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
+    "Exported function %0 must not contain a resource in parameter or return type.");
+  std::string escaped;
+  llvm::raw_string_ostream os(escaped);
+  dxilutil::PrintEscapedString(name, os);
+  Diags.Report(DiagID) << os.str();
+}
+
 void CGMSHLSLRuntime::FinishCodeGen() {
   // Library don't have entry.
   if (!m_bIsLib) {
@@ -4565,6 +4600,30 @@ void CGMSHLSLRuntime::FinishCodeGen() {
     }
   }
 
+  // Disallow resource arguments in (non-entry) function exports
+  if (m_bIsLib) {
+    for (Function &f : m_pHLModule->GetModule()->functions()) {
+      // Skip llvm intrinsics, non-external linkage, entry/patch constant func, and HL intrinsics
+      if (!f.isIntrinsic() &&
+          f.getLinkage() == GlobalValue::LinkageTypes::ExternalLinkage &&
+          !m_pHLModule->HasDxilFunctionProps(&f) &&
+          !m_pHLModule->IsPatchConstantShader(&f) &&
+          GetHLOpcodeGroup(&f) == HLOpcodeGroup::NotHL) {
+        // Verify no resources in param/return types
+        if (ContainsDisallowedTypeForExport(f.getReturnType())) {
+          ReportDisallowedTypeInExportParam(CGM, f.getName());
+          continue;
+        }
+        for (auto &Arg : f.args()) {
+          if (ContainsDisallowedTypeForExport(Arg.getType())) {
+            ReportDisallowedTypeInExportParam(CGM, f.getName());
+            break;
+          }
+        }
+      }
+    }
+  }
+
   // Do simple transform to make later lower pass easier.
   SimpleTransformForHLDXIR(m_pHLModule->GetModule());
 

+ 0 - 3
tools/clang/test/CodeGenHLSL/lib_cs_entry.hlsl

@@ -8,9 +8,6 @@
 // CHECK: RotateMat
 // CHECK: StoreOutputMat
 
-// Make sure cloned function exist.
-// CHECK: @"\01?entry
-
 // Make sure function props exist.
 // CHECK: !dx.entryPoints = !{{{.*}}, {{.*}}}
 

+ 0 - 4
tools/clang/test/CodeGenHLSL/lib_cs_entry3.hlsl

@@ -4,10 +4,6 @@
 // CHECK: @entry(
 // CHECK: @entry2(
 
-// Make sure cloned function exist.
-// CHECK: @"\01?entry
-// CHECK: @"\01?entry2
-
 // Make sure function props exist.
 // CHECK: !dx.entryPoints = !{{{.*}}, {{.*}}, {{.*}}}
 

+ 1 - 11
tools/clang/test/CodeGenHLSL/lib_entries.hlsl

@@ -7,10 +7,6 @@
 // CHECK: dx.op.threadId
 // CHECK: dx.op.groupId
 
-
-// Make sure cloned function exist.
-// CHECK: @"\01?ps_main
-
 // Make sure entry function exist.
 // CHECK: @gs_main()
 // Make sure signatures are lowered.
@@ -55,16 +51,10 @@
 // Finish ps_main
 // CHECK: ret void
 
-// Make sure cloned function signatures are not lowered.
-// CHECK-NOT: call float @dx.op.loadInput
-// CHECK-NOT: call void @dx.op.storeOutput
-
-
-
 
 // Make sure function entrys exist.
 // CHECK: !dx.entryPoints = !{{{.*}}, {{.*}}, {{.*}}, {{.*}}, {{.*}}, {{.*}}, {{.*}}}
-// Make sure cs don't have signature.
+// Make sure cs doesn't have signature.
 // CHECK: !"cs_main", null
 
 void StoreCSOutput(uint2 tid, uint2 gid);

+ 0 - 7
tools/clang/test/CodeGenHLSL/lib_entries2.hlsl

@@ -6,9 +6,6 @@
 // CHECK: dx.op.threadId
 // CHECK: dx.op.groupId
 
-// Make sure cloned function exist.
-// CHECK: @"\01?ps_main
-
 // Make sure entry function exist.
 // CHECK: @gs_main()
 // Make sure signatures are lowered.
@@ -51,10 +48,6 @@
 // Finish ps_main
 // CHECK: ret void
 
-// Make sure cloned function signatures are not lowered.
-// CHECK-NOT: call float @dx.op.loadInput
-// CHECK-NOT: call void @dx.op.storeOutput
-
 
 
 

+ 2 - 2
tools/clang/test/CodeGenHLSL/lib_resource.hlsl

@@ -1,8 +1,8 @@
 // RUN: %dxc -T lib_6_3 -auto-binding-space 11 %s | FileCheck %s
 
 // Make sure globals for resource exist.
-// CHECK: @"\01?g_txDiffuse@@3V?$Texture2D@V?$vector@M$03@@@@A" = external global %"class.Texture2D<vector<float, 4> >", align 4
-// CHECK: @"\01?g_samLinear@@3USamplerState@@A" = external global %struct.SamplerState, align 4
+// CHECK: @"\01?g_txDiffuse@@3V?$Texture2D@V?$vector@M$03@@@@A" = external constant %"class.Texture2D<vector<float, 4> >", align 4
+// CHECK: @"\01?g_samLinear@@3USamplerState@@A" = external constant %struct.SamplerState, align 4
 
 Texture2D    g_txDiffuse;
 SamplerState    g_samLinear;

+ 1 - 66
tools/clang/test/CodeGenHLSL/quick-test/d3dreflect/reflect-lib-1.hlsl

@@ -16,7 +16,7 @@ float4 function2(float4 x : POSITION) : SV_Position { return x + cbval1 + cbval3
 
 // CHECK: ID3D12LibraryReflection:
 // CHECK:   D3D12_LIBRARY_DESC:
-// CHECK:     FunctionCount: 4
+// CHECK:     FunctionCount: 3
 // CHECK:   ID3D12FunctionReflection:
 // CHECK:     D3D12_FUNCTION_DESC: Name: \01?function0@@YAM$f16@@Z
 // CHECK:       Shader Version: Library 6.3
@@ -114,71 +114,6 @@ float4 function2(float4 x : POSITION) : SV_Position { return x + cbval1 + cbval3
 // CHECK:         ReturnType: D3D_RETURN_TYPE_MIXED
 // CHECK:         Dimension: D3D_SRV_DIMENSION_BUFFER
 // CHECK:   ID3D12FunctionReflection:
-// CHECK:     D3D12_FUNCTION_DESC: Name: \01?function2@@YA?AV?$vector@M$03@@V1@@Z
-// CHECK:       Shader Version: Library 6.3
-// CHECK:       ConstantBuffers: 2
-// CHECK:       BoundResources: 2
-// CHECK:     Constant Buffers:
-// CHECK:       ID3D12ShaderReflectionConstantBuffer:
-// CHECK:         D3D12_SHADER_BUFFER_DESC: Name: $Globals
-// CHECK:           Type: D3D_CT_CBUFFER
-// CHECK:           Size: 16
-// CHECK:           Num Variables: 1
-// CHECK:         {
-// CHECK:           ID3D12ShaderReflectionVariable:
-// CHECK:             D3D12_SHADER_VARIABLE_DESC: Name: cbval1
-// CHECK:               Size: 4
-// CHECK:               uFlags: 0x2
-// CHECK:             ID3D12ShaderReflectionType:
-// CHECK:               D3D12_SHADER_TYPE_DESC: Name: float
-// CHECK:                 Class: D3D_SVC_SCALAR
-// CHECK:                 Type: D3D_SVT_FLOAT
-// CHECK:                 Rows: 1
-// CHECK:                 Columns: 1
-// CHECK:             CBuffer: $Globals
-// CHECK:         }
-// CHECK:       ID3D12ShaderReflectionConstantBuffer:
-// CHECK:         D3D12_SHADER_BUFFER_DESC: Name: MyCB
-// CHECK:           Type: D3D_CT_CBUFFER
-// CHECK:           Size: 32
-// CHECK:           Num Variables: 2
-// CHECK:         {
-// CHECK:           ID3D12ShaderReflectionVariable:
-// CHECK:             D3D12_SHADER_VARIABLE_DESC: Name: cbval2
-// CHECK:               Size: 16
-// CHECK:               uFlags: 0x2
-// CHECK:             ID3D12ShaderReflectionType:
-// CHECK:               D3D12_SHADER_TYPE_DESC: Name: int4
-// CHECK:                 Class: D3D_SVC_VECTOR
-// CHECK:                 Type: D3D_SVT_INT
-// CHECK:                 Rows: 1
-// CHECK:                 Columns: 4
-// CHECK:             CBuffer: MyCB
-// CHECK:           ID3D12ShaderReflectionVariable:
-// CHECK:             D3D12_SHADER_VARIABLE_DESC: Name: cbval3
-// CHECK:               Size: 16
-// CHECK:               StartOffset: 16
-// CHECK:               uFlags: 0x2
-// CHECK:             ID3D12ShaderReflectionType:
-// CHECK:               D3D12_SHADER_TYPE_DESC: Name: int4
-// CHECK:                 Class: D3D_SVC_VECTOR
-// CHECK:                 Type: D3D_SVT_INT
-// CHECK:                 Rows: 1
-// CHECK:                 Columns: 4
-// CHECK:             CBuffer: MyCB
-// CHECK:         }
-// CHECK:     Bound Resources:
-// CHECK:       D3D12_SHADER_BUFFER_DESC: Name: $Globals
-// CHECK:         Type: D3D_SIT_CBUFFER
-// CHECK:         uID: 0
-// CHECK:         Dimension: D3D_SRV_DIMENSION_UNKNOWN
-// CHECK:       D3D12_SHADER_BUFFER_DESC: Name: MyCB
-// CHECK:         Type: D3D_SIT_CBUFFER
-// CHECK:         uID: 1
-// CHECK:         BindPoint: 11
-// CHECK:         Space: 2
-// CHECK:         Dimension: D3D_SRV_DIMENSION_UNKNOWN
-// CHECK:   ID3D12FunctionReflection:
 // CHECK:     D3D12_FUNCTION_DESC: Name: function2
 // CHECK:       Shader Version: Vertex 6.3
 // CHECK:       ConstantBuffers: 2

+ 1 - 0
tools/clang/test/CodeGenHLSL/quick-test/lib_append_buf.hlsl

@@ -10,6 +10,7 @@ AppendStructuredBuffer<float4> appendUAVResource : register(u3);
 // Consume Structured Buffer (u4) 
 ConsumeStructuredBuffer<float4> consumeUAVResource : register(u4);
 
+[numthreads(1,1,1)]
 [shader("compute")]
 void test()
 {

+ 5 - 6
tools/clang/test/CodeGenHLSL/quick-test/lib_mat_cast.hlsl

@@ -3,12 +3,11 @@
 // CHECK: bitcast %class.matrix.float.4.3* {{.*}} to <12 x float>*
 
 float mat_array_test(in float4 in0,
-                                  in float4 in1,
-                                  float4x3 basisArray[2]) // cube map basis.
+                     in float4 in1,
+                     float4x3 basisArray[2]) // cube map basis.
 {
-uint index = in1.w;
+  uint index = in1.w;
 
-float3 outputs = mul(in0.xyz,
-            basisArray[index]);
-return outputs.z + basisArray[in1.y][in1.z].y;
+  float3 outputs = mul(in0.xyz, basisArray[index]);
+  return outputs.z + basisArray[in1.y][in1.z].y;
 }

+ 2 - 2
tools/clang/test/CodeGenHLSL/quick-test/lib_mat_entry8.hlsl

@@ -1,8 +1,8 @@
 // RUN: %dxc -T lib_6_3  %s | FileCheck %s
 
 // Make sure sure major change on matrix array works.
-// CHECK: bitcast [12 x float]* %4 to [2 x %class.matrix.float.3.2]*
-// CHECK: bitcast [12 x float]* %4 to [2 x %class.matrix.float.3.2]*
+// CHECK: bitcast [12 x float]* {{.*}} to [2 x %class.matrix.float.3.2]*
+// CHECK: bitcast [12 x float]* {{.*}} to [2 x %class.matrix.float.3.2]*
 // CHECK: bitcast %class.matrix.float.2.3* {{.*}} to <6 x float>*
 // CHECK: bitcast %class.matrix.float.2.3* {{.*}} to <6 x float>*
 

+ 4 - 2
tools/clang/test/CodeGenHLSL/quick-test/lib_res_param.hlsl

@@ -1,7 +1,9 @@
 // RUN: %dxc -T lib_6_3  %s | FileCheck %s
 
-// Make sure simple local resource array works.
-// CHECK: main
+// resources in return/params disallowed for lib_6_3
+// CHECK: error: Exported function
+// CHECK: resStruct
+// CHECK: must not contain a resource in parameter or return type
 
 struct T {
 RWByteAddressBuffer outputBuffer;

+ 3 - 4
tools/clang/test/CodeGenHLSL/quick-test/lib_select_res.hlsl

@@ -1,8 +1,7 @@
-// RUN: %dxc -T lib_6_3 -auto-binding-space 11 %s | FileCheck %s
+// RUN: %dxc -T lib_6_3 -Zi -auto-binding-space 11 %s | FileCheck %s
 
-// Make sure createHandleForLib is used for resource.
-// CHECK:call %dx.types.Handle @dx.op.createHandleForLib.struct.ByteAddressBuffer(i32 160
-// CHECK:call %dx.types.Handle @dx.op.createHandleForLib.struct.RWByteAddressBuffer(i32 160
+// resource uses must resolve to a single resource global variable (single rangeID)
+// CHECK: local resource not guaranteed to map to unique global resource
 
 RWByteAddressBuffer outputBuffer : register(u0);
 ByteAddressBuffer ReadBuffer : register(t0);

+ 1 - 1
tools/clang/test/CodeGenHLSL/quick-test/local_res_array2.hlsl

@@ -1,7 +1,7 @@
 // RUN: %dxc -T cs_6_0 -E main %s | FileCheck %s
 
 // Report error when cannot promote local resource.
-// CHECK: non-promotable local resource found
+// CHECK: local resource not guaranteed to map to unique global resource
 
 RWByteAddressBuffer outputBuffer;
 RWByteAddressBuffer outputBuffer2;

+ 15 - 0
tools/clang/test/CodeGenHLSL/quick-test/local_res_array3.hlsl

@@ -0,0 +1,15 @@
+// RUN: %dxc -T cs_6_0 -E main %s | FileCheck %s
+
+// Local resource array elements all map to same global resource, so this is legal.
+// CHECK: define void @main()
+
+RWByteAddressBuffer outputBuffer[3];
+uint i;
+[numthreads(8, 8, 1)]
+void main( uint2 id : SV_DispatchThreadID )
+{
+	RWByteAddressBuffer buffer[2];
+	buffer[0] = outputBuffer[2];
+	buffer[1] = outputBuffer[0];
+    buffer[i].Store(id.y, id.x);
+}

+ 1 - 1
tools/clang/test/CodeGenHLSL/quick-test/local_res_fail_map_error_msg.hlsl

@@ -2,7 +2,7 @@
 
 // Make sure line number is show for resource failed to map.
 
-// CHECK:line:11 col:10 local resource not guaranteed to map to unique global resource.
+// CHECK:local_res_fail_map_error_msg.hlsl:11:10: local resource not guaranteed to map to unique global resource
 
 SamplerState samp1 : register(s5);
 

+ 42 - 0
tools/clang/test/CodeGenHLSL/quick-test/no-phi-on-res.hlsl

@@ -0,0 +1,42 @@
+// RUN: %dxc -T lib_6_3 %s | FileCheck %s
+
+// Verify no phi on resource, handle, or anything
+
+// CHECK: entry:
+// CHECK-NOT: phi
+// CHECK: ret void
+
+
+Texture2D<float4> Textures[2] : register(t0, space0);
+RWTexture2D<float4> RWTextures[2] : register(u0, space0);
+
+static float4 load(uint resIdx, uint2 texel) {
+  if (((resIdx >> 8) & 3) == 1) {
+    return Textures[resIdx & 0xFF].Load(uint3(texel, 0));
+  }
+  if (((resIdx >> 8) & 3) == 2) {
+    return RWTextures[resIdx & 0xFF][texel];
+  }
+  return 0.0f;
+}
+
+static void store(uint resIdx, uint2 texel, float4 value) {
+  if (((resIdx >> 8) & 3) == 2) {
+    RWTextures[resIdx & 0xFF][texel] = value;
+  }
+  return;
+}
+
+RWTexture2D<float> OutBuf0 : register(u2, space0);
+
+[shader("raygeneration")]
+void main() {
+  uint2 launchIdx = DispatchRaysIndex();
+  const uint resIdx = 0x200;
+  float4 value = load(resIdx, launchIdx);
+  if (value.x > 10.0f) {
+    OutBuf0[launchIdx] = 0.0f;
+  }
+  store(resIdx, launchIdx, value);
+  return;
+}

+ 2 - 2
tools/clang/test/CodeGenHLSL/quick-test/raytracing_callable.hlsl

@@ -3,8 +3,8 @@
 // CHECK: ; S                                 sampler      NA          NA      S0             s1     1
 // CHECK: ; T                                 texture     f32          2d      T0             t1     1
 
-// CHECK:@"\01?T@@3V?$Texture2D@V?$vector@M$03@@@@A" = external global %"class.Texture2D<vector<float, 4> >", align 4
-// CHECK:@"\01?S@@3USamplerState@@A" = external global %struct.SamplerState, align 4
+// CHECK:@"\01?T@@3V?$Texture2D@V?$vector@M$03@@@@A" = external constant %"class.Texture2D<vector<float, 4> >", align 4
+// CHECK:@"\01?S@@3USamplerState@@A" = external constant %struct.SamplerState, align 4
 
 // CHECK: define void [[callable1:@"\\01\?callable1@[^\"]+"]](%struct.MyParam* noalias nocapture %param) #0 {
 // CHECK:   %[[i_0:[0-9]+]] = load %struct.SamplerState, %struct.SamplerState* @"\01?S@@3USamplerState@@A", align 4

+ 1 - 1
tools/clang/test/CodeGenHLSL/quick-test/raytracing_raygeneration.hlsl

@@ -2,7 +2,7 @@
 
 // CHECK: ; RTAS                              texture     i32         ras      T0             t5     1
 
-// CHECK:@"\01?RTAS@@3URaytracingAccelerationStructure@@A" = external global %struct.RaytracingAccelerationStructure, align 4
+// CHECK:@"\01?RTAS@@3URaytracingAccelerationStructure@@A" = external constant %struct.RaytracingAccelerationStructure, align 4
 
 // CHECK: define void [[raygen1:@"\\01\?raygen1@[^\"]+"]]() #0 {
 // CHECK:   %[[i_0:[0-9]+]] = load %struct.RaytracingAccelerationStructure, %struct.RaytracingAccelerationStructure* @"\01?RTAS@@3URaytracingAccelerationStructure@@A", align 4

+ 4 - 2
tools/clang/test/CodeGenHLSL/quick-test/res_in_struct.hlsl

@@ -1,7 +1,9 @@
 // RUN: %dxc -T lib_6_2 %s | FileCheck %s
 
-// make sure CreateHandleForLib is called.
-// CHECK: call %dx.types.Handle @"dx.op.createHandleForLib.class.Texture2D<vector<float, 4> >"(i32 160,
+// resources in return/params disallowed for lib_6_3
+// CHECK: error: Exported function
+// CHECK: emit
+// CHECK: must not contain a resource in parameter or return type.
 
 struct M {
    float3 a;

+ 21 - 12
tools/clang/test/CodeGenHLSL/quick-test/res_select2.hlsl

@@ -1,25 +1,33 @@
 // RUN: %dxc -T lib_6_3 -auto-binding-space 11 %s | FileCheck %s
 
-// Make sure phi/select of handle in lib.
-// CHECK-DAG: phi %dx.types.Handle
-// CHECK: phi %dx.types.Handle
-// CHECK: select i1 %{{[^,]+}}, %dx.types.Handle
-// CHECK-DAG: phi %dx.types.Handle
-// CHECK: phi %dx.types.Handle
-// CHECK: select i1 %{{[^,]+}}, %dx.types.Handle
-// CHECK-DAG: phi %dx.types.Handle
-// CHECK: phi %dx.types.Handle
+// Make sure index allocas are present for each dim of global resource
+// This handles local resource array with dynamic indexing
+// CHECK: alloca [6 x i32]
+// CHECK: alloca [6 x i32]
+// CHECK: alloca [6 x i32]
 
-RWBuffer<float4> a;
-RWBuffer<float4> b;
-RWBuffer<float4> c;
+// Make sure no phi/select of resource or handle in lib.
+// CHECK-NOT: phi %"class.
+// CHECK-NOT: phi %dx.types.Handle
+// CHECK-NOT: select i1 %{{[^,]+}}, %"class.
+// CHECK-NOT: select i1 %{{[^,]+}}, %dx.types.Handle
+// CHECK: ret <4 x float>
+
+RWBuffer<float4> BufArray[2][2][3];
 
 float4 test(int i, int j, int m) {
+  RWBuffer<float4> a = BufArray[m][0][0];
+  RWBuffer<float4> b = BufArray[0][m][1];
+  RWBuffer<float4> c = BufArray[0][1][m];
+  RWBuffer<float4> bufarr[2][3] = BufArray[m];
+
   RWBuffer<float4> buf = c;
   while (i > 9) {
      while (j < 4) {
         if (i < m)
           buf = b;
+        else
+          bufarr[i%2][j%3] = buf;
         buf[j] = i;
         j++;
      }
@@ -29,5 +37,6 @@ float4 test(int i, int j, int m) {
      i--;
   }
   buf[i] = j;
+  bufarr[m%2][j%3][j] = m;
   return j;
 }

+ 11 - 12
tools/clang/test/CodeGenHLSL/quick-test/res_select3.hlsl

@@ -1,14 +1,11 @@
 // RUN: %dxc -T lib_6_3 -auto-binding-space 11 %s | FileCheck %s
 
-// Make sure phi/select of handle in lib.
-// CHECK-DAG: phi %dx.types.Handle
-// CHECK: phi %dx.types.Handle
-// CHECK: select i1 %{{[^,]+}}, %dx.types.Handle
-// CHECK-DAG: phi %dx.types.Handle
-// CHECK: phi %dx.types.Handle
-// CHECK: select i1 %{{[^,]+}}, %dx.types.Handle
-// CHECK-DAG: phi %dx.types.Handle
-// CHECK: phi %dx.types.Handle
+// Make sure no phi/select of handle in lib.
+// CHECK: entry:
+// CHECK-NOT: phi %"class.
+// CHECK-NOT: phi %dx.types.Handle
+// CHECK-NOT: select i1 %{{[^,]+}}, %"class.
+// CHECK-NOT: select i1 %{{[^,]+}}, %dx.types.Handle
 
 // Make sure get dimensions returns 24
 // CHECK: ret i32 24
@@ -19,11 +16,13 @@ struct MyStruct {
   float3 c;
 };
 
-RWStructuredBuffer<MyStruct> a;
-RWStructuredBuffer<MyStruct> b;
-RWStructuredBuffer<MyStruct> c;
+RWStructuredBuffer<MyStruct> BufArray[3];
 
 uint test(int i, int j, int m) {
+  RWStructuredBuffer<MyStruct> a = BufArray[0];
+  RWStructuredBuffer<MyStruct> b = BufArray[1];
+  RWStructuredBuffer<MyStruct> c = BufArray[2];
+
   RWStructuredBuffer<MyStruct> buf = c;
   while (i > 9) {
      while (j < 4) {

+ 35 - 0
tools/clang/test/CodeGenHLSL/quick-test/res_select4.hlsl

@@ -0,0 +1,35 @@
+// RUN: %dxc -T lib_6_3 -auto-binding-space 11 %s | FileCheck %s
+
+// Make sure this fails
+// CHECK: error: local resource not guaranteed to map to unique global resource
+
+struct MyStruct {
+  float2 a;
+  int b;
+  float3 c;
+};
+
+RWStructuredBuffer<MyStruct> a;
+RWStructuredBuffer<MyStruct> b;
+RWStructuredBuffer<MyStruct> c;
+
+uint test(int i, int j, int m) {
+  RWStructuredBuffer<MyStruct> buf = c;
+  while (i > 9) {
+     while (j < 4) {
+        if (i < m)
+          buf = b;
+        buf[j].b = i;
+        j++;
+     }
+     if (m > j)
+       buf = a;
+     buf[m].b = i;
+     i--;
+  }
+  buf[i].b = j;
+  uint dim = 0;
+  uint stride = 0;
+  buf.GetDimensions(dim, stride);
+  return stride;
+}

+ 33 - 0
tools/clang/test/CodeGenHLSL/quick-test/res_select5.hlsl

@@ -0,0 +1,33 @@
+// RUN: %dxc -T lib_6_3 -auto-binding-space 11 %s | FileCheck %s
+
+// Make sure this fails
+// CHECK: error: local resource not guaranteed to map to unique global resource
+
+RWBuffer<float4> BufArray[2][2][3];
+RWBuffer<float4> Buf2;
+
+float4 test(int i, int j, int m) {
+  RWBuffer<float4> a = BufArray[m][0][0];
+  RWBuffer<float4> b = BufArray[0][m][1];
+  RWBuffer<float4> c = BufArray[0][1][m];
+  RWBuffer<float4> bufarr[2][3] = BufArray[m];
+
+  RWBuffer<float4> buf = c;
+  while (i > 9) {
+     while (j < 4) {
+        if (i < m)
+          buf = b;
+        else
+          bufarr[i%2][j%3] = Buf2;  // Illegal: assign different global resource
+        buf[j] = i;
+        j++;
+     }
+     if (m > j)
+       buf = a;
+     buf[m] = i;
+     i--;
+  }
+  buf[i] = j;
+  bufarr[m%2][j%3][j] = m;
+  return j;
+}

+ 2 - 3
tools/clang/test/CodeGenHLSL/selectObj4.hlsl

@@ -1,9 +1,8 @@
 // RUN: %dxc -E main -T cs_6_0 %s | FileCheck %s
 
 // Make sure select on resource index.
-// TODO: transform phi into selectInst.
-// CHECK: phi i32 [ 2, {{.*}} ], [ 1, {{.*}} ]
-// CHECK: phi i32 [ 0, {{.*}} ], [ 3, {{.*}} ]
+// CHECK: select i1 {{.*}}, i32 2, i32 1
+// CHECK: select i1 {{.*}}, i32 0, i32 3
 
 
 RWStructuredBuffer<float2x2> o[6];

+ 4 - 2
tools/clang/test/CodeGenHLSL/shader-compat-suite/ignore_line_directives.hlsl

@@ -15,6 +15,8 @@ RWStructuredBuffer<float2> buf1;
 #line 0 "test2.h"
 
 void Store(bool bBufX, float2 v, uint idx) {
-  RWStructuredBuffer<float2> buf = bBufX ? buf0: buf1;
-  buf[idx] = v;
+  if (bBufX)
+    buf0[idx] = v;
+  else
+    buf1[idx] = v;
 }

+ 4 - 2
tools/clang/test/CodeGenHLSL/shader-compat-suite/lib_out_param_res.hlsl

@@ -1,7 +1,9 @@
 // RUN: %dxc -T lib_6_3 -auto-binding-space 11 %s | FileCheck %s
 
-// CHECK: call void @"\01?GetBuf@@YA?AV?$Buffer@V?$vector@M$03@@@@XZ"(%"class.Buffer<vector<float, 4> >"* nonnull sret {{.*}})
-// Make sure resource return type works.
+// resources in return/params disallowed for lib_6_3
+// CHECK: error: Exported function
+// CHECK: GetBuf
+// CHECK: must not contain a resource in parameter or return type
 
 Buffer<float4> GetBuf();
 

+ 4 - 3
tools/clang/test/CodeGenHLSL/shader-compat-suite/lib_out_param_res_imp.hlsl

@@ -1,8 +1,9 @@
 // RUN: %dxc -T lib_6_3 -auto-binding-space 11 %s | FileCheck %s
 
-// CHECK: load %"class.Buffer<vector<float, 4> >", %"class.Buffer<vector<float, 4> >"* @"\01?buf@@3V?$Buffer@V?$vector@M$03@@@@A"
-// CHECK: store %"class.Buffer<vector<float, 4> >"
-// Make sure resource return type works.
+// resources in return/params disallowed for lib_6_3
+// CHECK: error: Exported function
+// CHECK: GetBuf
+// CHECK: must not contain a resource in parameter or return type
 
 Buffer<float4> buf;
 

+ 2 - 2
tools/clang/test/CodeGenHLSL/shader-compat-suite/lib_res_sel.hlsl

@@ -1,7 +1,7 @@
 // RUN: %dxc -T lib_6_3 -auto-binding-space 11 %s | FileCheck %s
 
-// Make sure select resource works for lib profile.
-// CHECK: call %dx.types.Handle @"dx.op.createHandleForLib.class.RWStructuredBuffer<vector<float, 2> >"
+// resource uses must resolve to a single resource global variable (single rangeID)
+// CHECK: error: local resource not guaranteed to map to unique global resource
 
 RWStructuredBuffer<float2> buf0;
 RWStructuredBuffer<float2> buf1;

+ 5 - 3
tools/clang/test/CodeGenHLSL/shader-compat-suite/lib_ret_res.hlsl

@@ -1,7 +1,9 @@
-// RUN: %dxc -T lib_6_3 -auto-binding-space 11 %s | FileCheck %s
+// RUN: %dxc -T lib_6_3 -Zi -auto-binding-space 11 %s | FileCheck %s
 
-// Make sure handle store not unpack.
-// CHECK: store %struct.SamplerState {{.*}}, %struct.SamplerState*
+// resources in return/params disallowed for lib_6_3
+// CHECK: error: Exported function
+// CHECK: GetSampler
+// CHECK: must not contain a resource in parameter or return type
 
 SamplerState    g_samLinear;
 

+ 1 - 30
tools/clang/unittests/HLSL/DxilContainerTest.cpp

@@ -1100,7 +1100,7 @@ TEST_F(DxilContainerTest, CompileWhenOkThenCheckReflection1) {
       VERIFY_SUCCEEDED(containerReflection->GetPartReflection(i, IID_PPV_ARGS(&pLibraryReflection)));
       D3D12_LIBRARY_DESC LibDesc;
       VERIFY_SUCCEEDED(pLibraryReflection->GetDesc(&LibDesc));
-      VERIFY_ARE_EQUAL(LibDesc.FunctionCount, 4);
+      VERIFY_ARE_EQUAL(LibDesc.FunctionCount, 3);
       for (INT iFn = 0; iFn < (INT)LibDesc.FunctionCount; iFn++) {
         ID3D12FunctionReflection *pFunctionReflection = pLibraryReflection->GetFunctionByIndex(iFn);
         D3D12_FUNCTION_DESC FnDesc;
@@ -1168,35 +1168,6 @@ TEST_F(DxilContainerTest, CompileWhenOkThenCheckReflection1) {
               VERIFY_FAIL(L"Unexpected resource used");
             }
           }
-        } else if (Name.compare("\01?function2@@YAMV?$vector@M$03@@@Z") == 0) {
-          // library version of shader function is mangled
-          VERIFY_ARE_EQUAL(FnDesc.Version, EncodedVersion_lib_6_3);
-          VERIFY_ARE_EQUAL(FnDesc.ConstantBuffers, 2);
-          VERIFY_ARE_EQUAL(FnDesc.BoundResources, 2);
-          for (INT iCB = 0; iCB < (INT)FnDesc.BoundResources; iCB++) {
-            D3D12_SHADER_BUFFER_DESC cbDesc;
-            ID3D12ShaderReflectionConstantBuffer *pCBReflection = pFunctionReflection->GetConstantBufferByIndex(0);
-            VERIFY_SUCCEEDED(pCBReflection->GetDesc(&cbDesc));
-            std::string cbName = cbDesc.Name;
-            if (cbName.compare("$Globals") == 0) {
-              Ref1_CheckCBuffer_Globals(pCBReflection, cbDesc);
-            } else if (cbName.compare("MyCB") == 0) {
-              Ref1_CheckCBuffer_MyCB(pCBReflection, cbDesc);
-            }
-          }
-
-          for (INT iRes = 0; iRes < (INT)FnDesc.BoundResources; iRes++) {
-            D3D12_SHADER_INPUT_BIND_DESC resDesc;
-            pFunctionReflection->GetResourceBindingDesc(iRes, &resDesc);
-            std::string resName = resDesc.Name;
-            if (resName.compare("$Globals") == 0) {
-              Ref1_CheckBinding_Globals(resDesc);
-            } else if (resName.compare("MyCB") == 0) {
-              Ref1_CheckBinding_MyCB(resDesc);
-            } else {
-              VERIFY_FAIL(L"Unexpected resource used");
-            }
-          }
         } else if (Name.compare("function2") == 0) {
           // shader function with unmangled name
           VERIFY_ARE_EQUAL(FnDesc.Version, EncodedVersion_vs_6_3);

+ 15 - 12
tools/clang/unittests/HLSL/LinkerTest.cpp

@@ -47,13 +47,13 @@ public:
   TEST_METHOD(RunLinkMatArrayParam);
   TEST_METHOD(RunLinkMatParam);
   TEST_METHOD(RunLinkMatParamToLib);
-  TEST_METHOD(RunLinkResRet);
+  //TEST_METHOD(RunLinkResRet);
   TEST_METHOD(RunLinkToLib);
   TEST_METHOD(RunLinkToLibExport);
   TEST_METHOD(RunLinkFailReDefineGlobal);
   TEST_METHOD(RunLinkFailProfileMismatch);
   TEST_METHOD(RunLinkFailEntryNoProps);
-  TEST_METHOD(RunLinkFailSelectRes);
+  //TEST_METHOD(RunLinkFailSelectRes);
   TEST_METHOD(RunLinkToLibWithUnresolvedFunctions);
   TEST_METHOD(RunLinkToLibWithUnresolvedFunctionsExports);
   TEST_METHOD(RunLinkToLibWithExportNamesSwapped);
@@ -359,6 +359,7 @@ TEST_F(LinkerTest, RunLinkMatParamToLib) {
        {"bitcast <12 x float>* %1 to %class.matrix.float.4.3*"}, {});
 }
 
+#if 0 // unsupported for lib_6_3, but possibly future or offline-only target
 TEST_F(LinkerTest, RunLinkResRet) {
   CComPtr<IDxcBlob> pEntryLib;
   CompileLib(L"..\\CodeGenHLSL\\shader-compat-suite\\lib_out_param_res.hlsl", &pEntryLib);
@@ -376,16 +377,17 @@ TEST_F(LinkerTest, RunLinkResRet) {
 
   Link(L"test", L"ps_6_0", pLinker, {libName, libName2}, {}, {"alloca"});
 }
+#endif
 
 TEST_F(LinkerTest, RunLinkToLib) {
   LPCWSTR option[] = {L"-Zi"};
 
   CComPtr<IDxcBlob> pEntryLib;
-  CompileLib(L"..\\CodeGenHLSL\\shader-compat-suite\\lib_out_param_res.hlsl",
+  CompileLib(L"..\\CodeGenHLSL\\quick-test\\lib_mat_entry2.hlsl",
              &pEntryLib, option, 1);
   CComPtr<IDxcBlob> pLib;
   CompileLib(
-      L"..\\CodeGenHLSL\\shader-compat-suite\\lib_out_param_res_imp.hlsl",
+      L"..\\CodeGenHLSL\\quick-test\\lib_mat_cast2.hlsl",
       &pLib, option, 1);
 
   CComPtr<IDxcLinker> pLinker;
@@ -397,17 +399,16 @@ TEST_F(LinkerTest, RunLinkToLib) {
   LPCWSTR libName2 = L"test";
   RegisterDxcModule(libName2, pLib, pLinker);
 
-  Link(L"", L"lib_6_2", pLinker, {libName, libName2}, {"!llvm.dbg.cu"}, {});
+  Link(L"", L"lib_6_3", pLinker, {libName, libName2}, {"!llvm.dbg.cu"}, {});
 }
 
 TEST_F(LinkerTest, RunLinkToLibExport) {
   CComPtr<IDxcBlob> pEntryLib;
-  CompileLib(L"..\\CodeGenHLSL\\shader-compat-suite\\lib_out_param_res.hlsl",
+  CompileLib(L"..\\CodeGenHLSL\\quick-test\\lib_mat_entry2.hlsl",
              &pEntryLib);
   CComPtr<IDxcBlob> pLib;
-  CompileLib(
-      L"..\\CodeGenHLSL\\shader-compat-suite\\lib_out_param_res_imp.hlsl",
-      &pLib);
+  CompileLib(L"..\\CodeGenHLSL\\quick-test\\lib_mat_cast2.hlsl",
+             &pLib);
 
   CComPtr<IDxcLinker> pLinker;
   CreateLinker(&pLinker);
@@ -418,11 +419,12 @@ TEST_F(LinkerTest, RunLinkToLibExport) {
   LPCWSTR libName2 = L"test";
   RegisterDxcModule(libName2, pLib, pLinker);
   Link(L"", L"lib_6_3", pLinker, {libName, libName2},
-    { "@\"\\01?renamed_test@@","@\"\\01?cloned_test@@","@test" },
-    { "@\"\\01?GetBuf", "@renamed_test", "@cloned_test" },
-    {L"-exports", L"renamed_test,cloned_test=\\01?test@@YA?AV?$vector@M$03@@I@Z;test"});
+    { "@\"\\01?renamed_test@@","@\"\\01?cloned_test@@","@main" },
+    { "@\"\\01?mat_test", "@renamed_test", "@cloned_test" },
+    {L"-exports", L"renamed_test,cloned_test=\\01?mat_test@@YA?AV?$vector@M$02@@V?$vector@M$03@@0AIAV?$matrix@M$03$02@@@Z;main"});
 }
 
+#if 0 // unsupported for lib_6_3, but possibly future or offline-only target
 TEST_F(LinkerTest, RunLinkFailSelectRes) {
   if (m_ver.SkipDxilVersion(1, 3)) return;
   CComPtr<IDxcBlob> pEntryLib;
@@ -442,6 +444,7 @@ TEST_F(LinkerTest, RunLinkFailSelectRes) {
   LinkCheckMsg(L"main", L"ps_6_0", pLinker, {libName, libName2},
                {"Local resource must map to global resource"});
 }
+#endif
 
 TEST_F(LinkerTest, RunLinkToLibWithUnresolvedFunctions) {
   LPCWSTR option[] = { L"-Zi" };

+ 4 - 2
utils/hct/hctdb.py

@@ -1489,11 +1489,13 @@ class db_dxil(object):
         add_pass('globaldce', 'GlobalDCE', 'Dead Global Elimination', [])
         add_pass('dynamic-vector-to-array', 'DynamicIndexingVectorToArray', 'Replace dynamic indexing vector with array', [
             {'n':'ReplaceAllVectors','t':'bool','c':1}])
-        add_pass('hlsl-dxil-legalize-resource-use', 'DxilLegalizeResourceUsePass', 'DXIL legalize resource use', [])
-        add_pass('hlsl-dxil-legalize-static-resource-use', 'DxilLegalizeStaticResourceUsePass', 'DXIL legalize static resource use', [])
+        add_pass('hlsl-dxil-promote-local-resources', 'DxilPromoteLocalResources', 'DXIL promote local resource use', [])
+        add_pass('hlsl-dxil-promote-static-resources', 'DxilPromoteStaticResources', 'DXIL promote static resource use', [])
+        add_pass('hlsl-dxil-legalize-resources', 'DxilLegalizeResources', 'DXIL legalize resource use', [])
         add_pass('hlsl-dxil-legalize-eval-operations', 'DxilLegalizeEvalOperations', 'DXIL legalize eval operations', [])
         add_pass('dxilgen', 'DxilGenerationPass', 'HLSL DXIL Generation', [
             {'n':'NotOptimized','t':'bool','c':1}])
+        add_pass('fail-undef-resource', 'FailUndefResource', 'Fail on undef resource use', [])
         add_pass('simplify-inst', 'SimplifyInst', 'Simplify Instructions', [])
         add_pass('mem2reg', 'PromotePass', 'Promote Memory to Register', [])
         add_pass('hlsl-dxil-precise', 'DxilPrecisePropagatePass', 'DXIL precise attribute propagate', [])

Энэ ялгаанд хэт олон файл өөрчлөгдсөн тул зарим файлыг харуулаагүй болно