Browse Source

Call init function for entry of lib profiles. (#3350)

* Call init function for entry of lib profiles.
Xiang Li 4 years ago
parent
commit
8e3a21c417

+ 6 - 1
lib/HLSL/DxilLinker.cpp

@@ -796,7 +796,10 @@ DxilLinkJob::Link(std::pair<DxilFunctionLinkInfo *, DxilLib *> &entryLinkPair,
   for (auto &it : m_functionDefs) {
     DxilFunctionLinkInfo *linkInfo = it.first;
     DxilLib *pLib = it.second;
-
+    // Skip constructor in entry lib which is already called for entries inside
+    // entry lib.
+    if (pLib == entryLinkPair.second)
+      continue;
     Function *F = linkInfo->func;
     if (pLib->IsInitFunc(F)) {
       Function *NewF = m_newFunctions[F->getName()];
@@ -1101,6 +1104,8 @@ void DxilLinkJob::RunPreparePass(Module &M) {
 
   // SROA
   PM.add(createSROAPass(/*RequiresDomTree*/false, /*SkipHLSLMat*/false));
+  // For static global handle.
+  PM.add(createLowerStaticGlobalIntoAlloca());
 
   // Remove MultiDimArray from function call arg.
   PM.add(createMultiDimArrayToOneDimArrayPass());

+ 168 - 24
lib/Transforms/Scalar/ScalarReplAggregatesHLSL.cpp

@@ -16,6 +16,7 @@
 
 #include "llvm/ADT/SetVector.h"
 #include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/DenseSet.h"
 #include "llvm/ADT/Statistic.h"
 #include "llvm/Analysis/AssumptionCache.h"
 #include "llvm/Analysis/Loads.h"
@@ -5695,7 +5696,6 @@ ModulePass *llvm::createSROA_Parameter_HLSL() {
 
 namespace {
 class LowerStaticGlobalIntoAlloca : public ModulePass {
-  HLModule *m_pHLModule;
   DebugInfoFinder m_DbgFinder;
 
 public:
@@ -5704,8 +5704,68 @@ public:
   const char *getPassName() const override { return "Lower static global into Alloca"; }
 
   bool runOnModule(Module &M) override {
-    m_pHLModule = &M.GetOrCreateHLModule();
     m_DbgFinder.processModule(M);
+    Type *handleTy = nullptr;
+    DxilTypeSystem *pTypeSys = nullptr;
+    SetVector<Function *> entryAndInitFunctionSet;
+    if (M.HasHLModule()) {
+      auto &HLM = M.GetHLModule();
+      pTypeSys = &HLM.GetTypeSystem();
+      handleTy = HLM.GetOP()->GetHandleType();
+      if (!HLM.GetShaderModel()->IsLib()) {
+        entryAndInitFunctionSet.insert(HLM.GetEntryFunction());
+        if (HLM.GetShaderModel()->IsHS()) {
+          entryAndInitFunctionSet.insert(HLM.GetPatchConstantFunction());
+        }
+      } else {
+        for (Function &F : M) {
+          if (!HLM.IsEntryThatUsesSignatures(&F))
+            continue;
+          entryAndInitFunctionSet.insert(&F);
+        }
+      }
+    } else {
+      DXASSERT(M.HasDxilModule(), "must have dxilModle or HLModule");
+      auto &DM = M.GetDxilModule();
+      pTypeSys = &DM.GetTypeSystem();
+      handleTy = DM.GetOP()->GetHandleType();
+      if (!DM.GetShaderModel()->IsLib()) {
+        entryAndInitFunctionSet.insert(DM.GetEntryFunction());
+        if (DM.GetShaderModel()->IsHS()) {
+          entryAndInitFunctionSet.insert(DM.GetPatchConstantFunction());
+        }
+      } else {
+        for (Function &F : M) {
+          if (!DM.IsEntryThatUsesSignatures(&F))
+            continue;
+          entryAndInitFunctionSet.insert(&F);
+        }
+      }
+    }
+
+    // Collect init functions for static globals.
+    if (GlobalVariable *Ctors = M.getGlobalVariable("llvm.global_ctors")) {
+      if (ConstantArray *CA =
+              dyn_cast<ConstantArray>(Ctors->getInitializer())) {
+        for (User::op_iterator i = CA->op_begin(), e = CA->op_end(); i != e;
+             ++i) {
+          if (isa<ConstantAggregateZero>(*i))
+            continue;
+          ConstantStruct *CS = cast<ConstantStruct>(*i);
+          if (isa<ConstantPointerNull>(CS->getOperand(1)))
+            continue;
+
+          // Must have a function or null ptr.
+          if (!isa<Function>(CS->getOperand(1)))
+            continue;
+          Function *Ctor = cast<Function>(CS->getOperand(1));
+          assert(Ctor->getReturnType()->isVoidTy() && Ctor->arg_size() == 0 &&
+                 "function type must be void (void)");
+          // Add Ctor.
+          entryAndInitFunctionSet.insert(Ctor);
+        }
+      }
+    }
 
     // Lower static global into allocas.
     std::vector<GlobalVariable *> staticGVs;
@@ -5713,12 +5773,17 @@ public:
       // only for non-constant static globals
       if (!dxilutil::IsStaticGlobal(&GV) || GV.isConstant())
         continue;
+      // Skip if GV used in functions other than entry.
+      if (!usedOnlyInEntry(&GV, entryAndInitFunctionSet))
+        continue;
       Type *EltTy = GV.getType()->getElementType();
       if (!EltTy->isAggregateType()) {
         staticGVs.emplace_back(&GV);
       } else {
+        EltTy = dxilutil::GetArrayEltTy(EltTy);
         // Lower static [array of] resources
-        if (dxilutil::IsHLSLObjectType(dxilutil::GetArrayEltTy(EltTy))) {
+        if (dxilutil::IsHLSLObjectType(EltTy) ||
+            EltTy == handleTy) {
           staticGVs.emplace_back(&GV);
         }
       }
@@ -5726,15 +5791,22 @@ public:
     bool bUpdated = false;
 
     const DataLayout &DL = M.getDataLayout();
+    // Create AI for each GV in each entry.
+    // Replace all users of GV with AI.
+    // Collect all users of GV within each entry.
+    // Remove unused AI in the end.
     for (GlobalVariable *GV : staticGVs) {
-      bUpdated |= lowerStaticGlobalIntoAlloca(GV, DL);
+      bUpdated |= lowerStaticGlobalIntoAlloca(GV, DL, *pTypeSys, entryAndInitFunctionSet);
     }
 
     return bUpdated;
   }
 
 private:
-  bool lowerStaticGlobalIntoAlloca(GlobalVariable *GV, const DataLayout &DL);
+  bool lowerStaticGlobalIntoAlloca(GlobalVariable *GV, const DataLayout &DL,
+                                   DxilTypeSystem &typeSys,
+                                   SetVector<Function *> &entryAndInitFunctionSet);
+  bool usedOnlyInEntry(Value *V, SetVector<Function *> &entryAndInitFunctionSet);
 };
 }
 
@@ -5858,34 +5930,106 @@ void PatchDebugInfo(DebugInfoFinder &DbgFinder, Function *F, GlobalVariable *GV,
   DIB.insertDeclare(AI, ConvertedLocalVar, Expr, Loc, AI->getNextNode());
 }
 
-bool LowerStaticGlobalIntoAlloca::lowerStaticGlobalIntoAlloca(GlobalVariable *GV, const DataLayout &DL) {
-  DxilTypeSystem &typeSys = m_pHLModule->GetTypeSystem();
-  unsigned size = DL.getTypeAllocSize(GV->getType()->getElementType());
-  hlutil::PointerStatus PS(GV, size, /*bLdStOnly*/ false);
+//Collect instructions using GV and the value used by the instruction.
+//For direct use, the value == GV
+//For constant operator like GEP/Bitcast, the value is the operator used by the instruction.
+//This requires recursion to unwrap nested constant operators using the GV.
+static void collectGVInstUsers(Value *V,
+                               DenseMap<Instruction *, Value *> &InstUserMap) {
+  for (User *U : V->users()) {
+    if (Instruction *I = dyn_cast<Instruction>(U)) {
+      InstUserMap[I] = V;
+    } else {
+      collectGVInstUsers(U, InstUserMap);
+    }
+  }
+}
+
+static Instruction *replaceGVUseWithAI(GlobalVariable *GV, AllocaInst *AI,
+                                       Value *U, IRBuilder<> &B) {
+  if (U == GV)
+    return AI;
+  if (GEPOperator *GEP = dyn_cast<GEPOperator>(U)) {
+    Instruction *PtrInst =
+        replaceGVUseWithAI(GV, AI, GEP->getPointerOperand(), B);
+    SmallVector<Value *, 2> Index(GEP->idx_begin(), GEP->idx_end());
+    return cast<Instruction>(B.CreateGEP(PtrInst, Index));
+  }
+
+  if (BitCastOperator *BCO = dyn_cast<BitCastOperator>(U)) {
+    Instruction *SrcInst = replaceGVUseWithAI(GV, AI, BCO->getOperand(0), B);
+    return cast<Instruction>(B.CreateBitCast(SrcInst, BCO->getType()));
+  }
+  DXASSERT(false, "unsupported user of static global");
+  return nullptr;
+}
+
+bool LowerStaticGlobalIntoAlloca::lowerStaticGlobalIntoAlloca(
+    GlobalVariable *GV, const DataLayout &DL, DxilTypeSystem &typeSys,
+    SetVector<Function *> &entryAndInitFunctionSet) {
   GV->removeDeadConstantUsers();
-  PS.analyze(typeSys, /*bStructElt*/ false);
-  bool NotStored = !PS.HasStored();
-  // Make sure GV only used in one function.
-  // Skip GV which don't have store.
-  if (PS.HasMultipleAccessingFunctions || NotStored)
-    return false;
+  // Create alloca for each entry.
+  DenseMap<Function *, AllocaInst *> allocaMap;
+  for (Function *F : entryAndInitFunctionSet) {
+    IRBuilder<> Builder(dxilutil::FindAllocaInsertionPt(F));
+    AllocaInst *AI = Builder.CreateAlloca(GV->getType()->getElementType());
+    allocaMap[F] = AI;
+    // Store initializer is exist.
+    if (GV->hasInitializer() && !isa<UndefValue>(GV->getInitializer())) {
+      Builder.CreateStore(GV->getInitializer(), GV);
+    }
+  }
 
-  Function *F = const_cast<Function*>(PS.AccessingFunction);
-  IRBuilder<> Builder(dxilutil::FindAllocaInsertionPt(F));
-  AllocaInst *AI = Builder.CreateAlloca(GV->getType()->getElementType());
+  DenseMap<Instruction *, Value *> InstUserMap;
+  collectGVInstUsers(GV, InstUserMap);
+
+  for (auto it : InstUserMap) {
+    Instruction *I = it.first;
+    Value *U = it.second;
 
-  // Store initializer is exist.
-  if (GV->hasInitializer() && !isa<UndefValue>(GV->getInitializer())) {
-    Builder.CreateStore(GV->getInitializer(), GV);
+    Function *F = I->getParent()->getParent();
+    AllocaInst *AI = allocaMap[F];
+
+    IRBuilder<> B(I);
+
+    Instruction *UI = replaceGVUseWithAI(GV, AI, U, B);
+    I->replaceUsesOfWith(U, UI);
   }
 
-  ReplaceConstantWithInst(GV, AI, Builder);
-  PatchDebugInfo(m_DbgFinder, F, GV, AI);
+  for (Function *F : entryAndInitFunctionSet) {
+    AllocaInst *AI = allocaMap[F];
+    if (AI->user_empty())
+      AI->eraseFromParent();
+    else
+      PatchDebugInfo(m_DbgFinder, F, GV, AI);
+  }
 
-  GV->eraseFromParent();
+  GV->removeDeadConstantUsers();
+  if (GV->user_empty())
+    GV->eraseFromParent();
   return true;
 }
 
+bool LowerStaticGlobalIntoAlloca::usedOnlyInEntry(
+    Value *V, SetVector<Function *> &entryAndInitFunctionSet) {
+  bool bResult = true;
+  for (User *U : V->users()) {
+    if (Instruction *I = dyn_cast<Instruction>(U)) {
+      Function *F = I->getParent()->getParent();
+
+      if (entryAndInitFunctionSet.count(F) == 0) {
+        bResult = false;
+        break;
+      }
+    } else {
+      bResult = usedOnlyInEntry(U, entryAndInitFunctionSet);
+      if (!bResult)
+        break;
+    }
+  }
+  return bResult;
+}
+
 char LowerStaticGlobalIntoAlloca::ID = 0;
 
 INITIALIZE_PASS(LowerStaticGlobalIntoAlloca, "static-global-to-alloca",

+ 36 - 28
tools/clang/lib/CodeGen/CGHLSLMS.cpp

@@ -3422,38 +3422,46 @@ void CGMSHLSLRuntime::FinishCodeGen() {
   TranslateRayQueryConstructor(HLM);
 
   bool bIsLib = HLM.GetShaderModel()->IsLib();
-  if (!bIsLib) {
-    // need this for "llvm.global_dtors"?
-    if (HLM.GetShaderModel()->IsHS()) {
-      if (Function *patchConstantFn = HLM.GetPatchConstantFunction()) {
-        // static globals are independent for entry function and patch constant function.
-        // Update static global in entry function will not affect value in patch constant function.
-        // So just call ctors for patch constant function too.
-        ProcessCtorFunctions(
-            M, "llvm.global_ctors",
-            patchConstantFn->getEntryBlock().getFirstInsertionPt(), false);
-        IRBuilder<> B(patchConstantFn->getEntryBlock().getFirstInsertionPt());
-        // For static globals which has const initialize value, copy it at
-        // beginning of patch constant function to avoid use value updated by
-        // entry function.
-        for (GlobalVariable &GV : M.globals()) {
-          if (GV.isConstant())
-            continue;
-          if (!GV.hasInitializer())
-            continue;
-          if (GV.getName() == "llvm.global_ctors")
-            continue;
-          Value *V = GV.getInitializer();
-          if (isa<UndefValue>(V))
-            continue;
-          B.CreateStore(V, &GV);
+  StringRef GlobalCtorName = "llvm.global_ctors";
+  llvm::SmallVector<llvm::Function *, 2> Ctors;
+  CollectCtorFunctions(M, GlobalCtorName, Ctors, CGM);
+  if (!Ctors.empty()) {
+    if (!bIsLib) {
+      // need this for "llvm.global_dtors"?
+      Function *patchConstantFn = nullptr;
+      if (HLM.GetShaderModel()->IsHS()) {
+        patchConstantFn = HLM.GetPatchConstantFunction();
+      }
+      ProcessCtorFunctions(M, Ctors, Entry.Func, patchConstantFn);
+      // remove the GV
+      if (GlobalVariable *GV = M.getGlobalVariable(GlobalCtorName))
+        GV->eraseFromParent();
+    } else {
+      // Call ctors for each entry.
+      DenseSet<Function *> processedPatchConstantFnSet;
+      for (auto &Entry : entryFunctionMap) {
+        Function *F = Entry.second.Func;
+        Function *patchConstFunc = nullptr;
+        auto AttrIter = HSEntryPatchConstantFuncAttr.find(F);
+        if (AttrIter != HSEntryPatchConstantFuncAttr.end()) {
+          StringRef funcName = AttrIter->second->getFunctionName();
+
+          auto PatchEntry = patchConstantFunctionMap.find(funcName);
+          if (PatchEntry != patchConstantFunctionMap.end() &&
+              PatchEntry->second.NumOverloads == 1) {
+            patchConstFunc = PatchEntry->second.Func;
+            // Each patchConstFunc should only be processed once.
+            if (patchConstFunc &&
+                processedPatchConstantFnSet.count(patchConstFunc) == 0)
+              processedPatchConstantFnSet.insert(patchConstFunc);
+            else
+              patchConstFunc = nullptr;
+          }
         }
+        ProcessCtorFunctions(M, Ctors, F, patchConstFunc);
       }
     }
-    ProcessCtorFunctions(M, "llvm.global_ctors",
-                         Entry.Func->getEntryBlock().getFirstInsertionPt(), true);
   }
-
   UpdateLinkage(HLM, CGM, m_ExportMap, entryFunctionMap,
                 patchConstantFunctionMap);
 

+ 108 - 7
tools/clang/lib/CodeGen/CGHLSLMSFinishCodeGen.cpp

@@ -2305,12 +2305,79 @@ bool BuildImmInit(Function *Ctor) {
   return true;
 }
 
+void CallCtorFunctionsAtInsertPt(llvm::Module &M,
+                                 llvm::SmallVector<llvm::Function *, 2> &Ctors,
+                                 Instruction *InsertPt) {
+  IRBuilder<> Builder(InsertPt);
+  for (Function *Ctor : Ctors) {
+    Builder.CreateCall(Ctor);
+  }
+}
+
+void CollectFunctionCallers(Function *F, DenseSet<Function *> &Callers) {
+  // worklist size max = call depth
+  SmallVector<Function *, 8> worklist;
+  worklist.push_back(F);
+  // add callers
+  while (worklist.size()) {
+    Function *F = worklist.pop_back_val();
+    for (User *U : F->users()) {
+      if (CallInst *CI = dyn_cast<CallInst>(U)) {
+        Function *Caller = CI->getParent()->getParent();
+        if (Callers.insert(Caller).second == true) {
+          // new caller
+          worklist.push_back(Caller);
+        }
+      }
+    }
+  }
+}
+
+DenseSet<Function *> CollectExternalFunctionCallers(Module &M) {
+  DenseSet<Function *> Callers;
+  for (Function &F : M) {
+    if (!F.isIntrinsic() && F.isDeclaration() &&
+        hlsl::GetHLOpcodeGroup(&F) == hlsl::HLOpcodeGroup::NotHL) {
+      CollectFunctionCallers(&F, Callers);
+    }
+  }
+  return Callers;
+}
+
+// If static initializers contain calls to external functions, this can
+// introduce inter-module init function ordering dependencies.  Some
+// dependencies may even introduce contradictions.  Creating and implementing an
+// intuitive standard approach to solve this is likely quite difficult.  Better
+// to disallow the ambiguous and unlikely case for now.
+bool IsValidCtorFunction(Function *F, DenseSet<Function *> &Callers) {
+  return Callers.count(F) == 0;
+}
+
+void ReportInitStaticGlobalWithExternalFunction(
+    clang::CodeGen ::CodeGenModule &CGM, StringRef name) {
+  clang::DiagnosticsEngine &Diags = CGM.getDiags();
+  unsigned DiagID = Diags.getCustomDiagID(
+      clang::DiagnosticsEngine::Error,
+      "Initializer for static global %0 makes disallowed call to external function.");
+  std::string escaped;
+  llvm::raw_string_ostream os(escaped);
+  size_t end = name.find_first_of('@');
+  if (end != StringRef::npos)
+    name = name.substr(0, end);
+  StringRef prefix = "\01??__E";
+  if (name.startswith(prefix))
+    name = name.substr(prefix.size());
+
+  dxilutil::PrintEscapedString(name, os);
+  Diags.Report(DiagID) << os.str();
+}
 } // namespace
 
 namespace CGHLSLMSHelper {
 
-void ProcessCtorFunctions(llvm::Module &M, StringRef globalName,
-                          Instruction *InsertPt, bool bRemoveGlobal) {
+void CollectCtorFunctions(llvm::Module &M, llvm::StringRef globalName,
+                          llvm::SmallVector<llvm::Function *, 2> &Ctors,
+                          clang::CodeGen::CodeGenModule &CGM) {
   // add global call to entry func
   GlobalVariable *GV = M.getGlobalVariable(globalName);
   if (!GV)
@@ -2318,7 +2385,9 @@ void ProcessCtorFunctions(llvm::Module &M, StringRef globalName,
   ConstantArray *CA = dyn_cast<ConstantArray>(GV->getInitializer());
   if (!CA)
     return;
-  IRBuilder<> Builder(InsertPt);
+
+  DenseSet<Function *> Callers = CollectExternalFunctionCallers(M);
+
   for (User::op_iterator i = CA->op_begin(), e = CA->op_end(); i != e; ++i) {
     if (isa<ConstantAggregateZero>(*i))
       continue;
@@ -2339,7 +2408,11 @@ void ProcessCtorFunctions(llvm::Module &M, StringRef globalName,
         // Try to build imm initilizer.
         // If not work, add global call to entry func.
         if (BuildImmInit(F) == false) {
-          Builder.CreateCall(F);
+          if (IsValidCtorFunction(F, Callers)) {
+            Ctors.emplace_back(F);
+          } else {
+            ReportInitStaticGlobalWithExternalFunction(CGM, F->getName());
+          }
         }
       } else {
         DXASSERT(isa<ReturnInst>(&(*I)),
@@ -2347,10 +2420,38 @@ void ProcessCtorFunctions(llvm::Module &M, StringRef globalName,
       }
     }
   }
-  // remove the GV
-  if (bRemoveGlobal) {
-    GV->eraseFromParent();
+}
+
+void ProcessCtorFunctions(llvm::Module &M,
+                          llvm::SmallVector<llvm::Function *, 2> &Ctors,
+                          llvm::Function *Entry,
+                          llvm::Function *PatchConstantFn) {
+  if (PatchConstantFn) {
+    // static globals are independent for entry function and patch constant
+    // function. Update static global in entry function will not affect
+    // value in patch constant function. So just call ctors for patch
+    // constant function too.
+    CallCtorFunctionsAtInsertPt(
+        M, Ctors, PatchConstantFn->getEntryBlock().getFirstInsertionPt());
+    IRBuilder<> B(PatchConstantFn->getEntryBlock().getFirstInsertionPt());
+    // For static globals which has const initialize value, copy it at
+    // beginning of patch constant function to avoid use value updated by
+    // entry function.
+    for (GlobalVariable &GV : M.globals()) {
+      if (GV.isConstant())
+        continue;
+      if (!GV.hasInitializer())
+        continue;
+      if (GV.getName() == "llvm.global_ctors")
+        continue;
+      Value *V = GV.getInitializer();
+      if (isa<UndefValue>(V))
+        continue;
+      B.CreateStore(V, &GV);
+    }
   }
+  CallCtorFunctionsAtInsertPt(M, Ctors,
+                              Entry->getEntryBlock().getFirstInsertionPt());
 }
 
 void FinishCBuffer(HLModule &HLM, llvm::Type *CBufferType,

+ 8 - 2
tools/clang/lib/CodeGen/CGHLSLMSHelper.h

@@ -196,8 +196,14 @@ void FinishCBuffer(
     std::unordered_map<llvm::Constant *, hlsl::DxilFieldAnnotation>
         &AnnotationMap);
 
-void ProcessCtorFunctions(llvm::Module &M, llvm::StringRef globalName,
-                          llvm::Instruction *InsertPt, bool bRemoveGlobal);
+void ProcessCtorFunctions(llvm::Module &M,
+                          llvm::SmallVector<llvm::Function *, 2> &Ctors,
+                          llvm::Function *Entry,
+                          llvm::Function *PatchConstantFn);
+
+void CollectCtorFunctions(llvm::Module &M, llvm::StringRef globalName,
+                          llvm::SmallVector<llvm::Function *, 2> &Ctors,
+                          clang::CodeGen::CodeGenModule &CGM);
 
 void TranslateRayQueryConstructor(hlsl::HLModule &HLM);
 

+ 52 - 2
tools/clang/test/HLSLFileCheck/d3dreflect/lib_global.hlsl

@@ -164,13 +164,53 @@
 // CHECK-NEXT:     D3D12_FUNCTION_DESC: Name: test
 // CHECK-NEXT:       Shader Version: Pixel 6.3
 // CHECK:       Flags: 0
-// CHECK-NEXT:       ConstantBuffers: 1
-// CHECK-NEXT:       BoundResources: 3
+// CHECK-NEXT:       ConstantBuffers: 2
+// CHECK-NEXT:       BoundResources: 4
 // CHECK-NEXT:       FunctionParameterCount: 0
 // CHECK-NEXT:       HasReturn: FALSE
 // CHECK-NEXT:     Constant Buffers:
 // CHECK-NEXT:       ID3D12ShaderReflectionConstantBuffer:
 // CHECK-NEXT:         D3D12_SHADER_BUFFER_DESC: Name: X
+// CHECK-NEXT:           Type: D3D_CT_CBUFFER
+// CHECK-NEXT:           Size: 16
+// CHECK-NEXT:           uFlags: 0
+// CHECK-NEXT:           Num Variables: 2
+// CHECK-NEXT:         {
+// CHECK-NEXT:           ID3D12ShaderReflectionVariable:
+// CHECK-NEXT:             D3D12_SHADER_VARIABLE_DESC: Name: e
+// CHECK-NEXT:               Size: 2
+// CHECK-NEXT:               StartOffset: 0
+// CHECK-NEXT:               uFlags: 0
+// CHECK-NEXT:               DefaultValue: <nullptr>
+// CHECK-NEXT:             ID3D12ShaderReflectionType:
+// CHECK-NEXT:               D3D12_SHADER_TYPE_DESC: Name: float16_t
+// CHECK-NEXT:                 Class: D3D_SVC_SCALAR
+// CHECK-NEXT:                 Type: D3D_SVT_FLOAT16
+// CHECK-NEXT:                 Elements: 0
+// CHECK-NEXT:                 Rows: 1
+// CHECK-NEXT:                 Columns: 1
+// CHECK-NEXT:                 Members: 0
+// CHECK-NEXT:                 Offset: 0
+// CHECK-NEXT:             CBuffer: X
+// CHECK-NEXT:           ID3D12ShaderReflectionVariable:
+// CHECK-NEXT:             D3D12_SHADER_VARIABLE_DESC: Name: f
+// CHECK-NEXT:               Size: 2
+// CHECK-NEXT:               StartOffset: 2
+// CHECK-NEXT:               uFlags: (D3D_SVF_USED)
+// CHECK-NEXT:               DefaultValue: <nullptr>
+// CHECK-NEXT:             ID3D12ShaderReflectionType:
+// CHECK-NEXT:               D3D12_SHADER_TYPE_DESC: Name: float16_t
+// CHECK-NEXT:                 Class: D3D_SVC_SCALAR
+// CHECK-NEXT:                 Type: D3D_SVT_FLOAT16
+// CHECK-NEXT:                 Elements: 0
+// CHECK-NEXT:                 Rows: 1
+// CHECK-NEXT:                 Columns: 1
+// CHECK-NEXT:                 Members: 0
+// CHECK-NEXT:                 Offset: 0
+// CHECK-NEXT:             CBuffer: X
+// CHECK-NEXT:         }
+// CHECK-NEXT:       ID3D12ShaderReflectionConstantBuffer:
+// CHECK-NEXT:         D3D12_SHADER_BUFFER_DESC: Name: X
 // CHECK-NEXT:           Type: D3D_CT_RESOURCE_BIND_INFO
 // CHECK-NEXT:           Size: 56
 // CHECK-NEXT:           uFlags: 0
@@ -250,6 +290,16 @@
 // CHECK-NEXT:             CBuffer: X
 // CHECK-NEXT:         }
 // CHECK-NEXT:     Bound Resources:
+// CHECK-NEXT:       D3D12_SHADER_BUFFER_DESC: Name: X
+// CHECK-NEXT:               Type: D3D_SIT_CBUFFER
+// CHECK-NEXT:               uID: 0
+// CHECK-NEXT:               BindCount: 1
+// CHECK-NEXT:               BindPoint: 4294967295
+// CHECK-NEXT:               Space: 4294967295
+// CHECK-NEXT:               ReturnType: <unknown: 0>
+// CHECK-NEXT:               Dimension: D3D_SRV_DIMENSION_UNKNOWN
+// CHECK-NEXT:               NumSamples (or stride): 0
+// CHECK-NEXT:               uFlags: (D3D_SIF_USERPACKED)
 // CHECK-NEXT:       D3D12_SHADER_BUFFER_DESC: Name: g_samLinear
 // CHECK-NEXT:         Type: D3D_SIT_SAMPLER
 // CHECK-NEXT:         uID: 0

+ 35 - 0
tools/clang/test/HLSLFileCheck/hlsl/intrinsics/createHandleFromHeap/dynamic_res_global_for_lib.hlsl

@@ -0,0 +1,35 @@
+// RUN: %dxc -T lib_6_6 %s | %FileCheck %s
+
+// Make sure each entry get 2 createHandleFromHeap.
+// CHECK:define void
+// CHECK:call %dx.types.Handle @dx.op.createHandleFromHeap(i32 218, i32 %{{.*}}, i1 false, i1 false)
+// CHECK:call %dx.types.Handle @dx.op.createHandleFromHeap(i32 218, i32 %{{.*}}, i1 false, i1 false)
+// CHECK:define void
+// CHECK:call %dx.types.Handle @dx.op.createHandleFromHeap(i32 218, i32 %{{.*}}, i1 false, i1 false)
+// CHECK:call %dx.types.Handle @dx.op.createHandleFromHeap(i32 218, i32 %{{.*}}, i1 false, i1 false)
+
+uint ID;
+static const RWBuffer<float>           g_result      = ResourceDescriptorHeap[ID];
+static ByteAddressBuffer         g_rawBuf      = ResourceDescriptorHeap[ID+1];
+static float x = ID + 3;
+
+// TODO: support array.
+//  static Buffer<float> g_bufs[2] = {ResourceDescriptorHeap[ID+2], ResourceDescriptorHeap[ID+3]};
+
+[NumThreads(1, 1, 1)]
+[RootSignature("RootFlags(CBV_SRV_UAV_HEAP_DIRECTLY_INDEXED | SAMPLER_HEAP_DIRECTLY_INDEXED), RootConstants(num32BitConstants=1, b0))")]
+void csmain(uint ix : SV_GroupIndex)
+{
+  g_result[ix] = g_rawBuf.Load<float>(ix);// + g_bufs[0].Load(ix);
+}
+// export foo to make sure init function not removed.
+export float foo(uint i) {
+  return x + i;
+}
+
+[NumThreads(1, 1, 1)]
+[RootSignature("RootFlags(CBV_SRV_UAV_HEAP_DIRECTLY_INDEXED | SAMPLER_HEAP_DIRECTLY_INDEXED), RootConstants(num32BitConstants=1, b0)")]
+void csmain2(uint ix : SV_GroupIndex)
+{
+  g_result[ix] = g_rawBuf.Load<float>(ix+ID);
+}

+ 10 - 0
tools/clang/test/HLSLFileCheck/hlsl/types/modifiers/global/init_static_global_with_external_function.hlsl

@@ -0,0 +1,10 @@
+// RUN: %dxc -E main -T lib_6_3 %s | FileCheck %s
+// CHECK:Initializer for static global g makes disallowed call to external function.
+
+float foo();
+
+static float g = foo();
+
+export float bar() {
+  return g;
+}

+ 2 - 2
tools/clang/test/HLSLFileCheck/hlsl/types/modifiers/static/staticGlobals.hlsl

@@ -6,9 +6,9 @@
 // CHECK: [3 x float] [float 6.000000e+00, float 0.000000e+00, float 0.000000e+00]
 // CHECK: [3 x float] [float 7.000000e+00, float 0.000000e+00, float 0.000000e+00]
 // CHECK: [3 x float] [float 8.000000e+00, float 0.000000e+00, float 0.000000e+00]
-// CHECK: [4 x float] [float 5.000000e+00, float 6.000000e+00, float 7.000000e+00, float 8.000000e+00]
-// CHECK: [16 x float] [float 1.500000e+01, float 1.500000e+01, float 1.500000e+01, float 1.500000e+01, float 1.600000e+01, float 1.600000e+01, float 1.600000e+01, float 1.600000e+01, float 1.700000e+01, float 1.700000e+01, float 1.700000e+01, float 1.700000e+01, float 1.800000e+01, float 1.800000e+01, float 1.800000e+01, float 1.800000e+01]
 // CHECK: [16 x float] [float 0.000000e+00, float 1.000000e+00, float 2.000000e+00, float 3.000000e+00, float 0.000000e+00, float 1.000000e+00, float 2.000000e+00, float 3.000000e+00, float 0.000000e+00, float 1.000000e+00, float 2.000000e+00, float 3.000000e+00, float 0.000000e+00, float 1.000000e+00, float 2.000000e+00, float 3.000000e+00]
+// CHECK: [16 x float] [float 1.500000e+01, float 1.500000e+01, float 1.500000e+01, float 1.500000e+01, float 1.600000e+01, float 1.600000e+01, float 1.600000e+01, float 1.600000e+01, float 1.700000e+01, float 1.700000e+01, float 1.700000e+01, float 1.700000e+01, float 1.800000e+01, float 1.800000e+01, float 1.800000e+01, float 1.800000e+01]
+// CHECK: [4 x float] [float 5.000000e+00, float 6.000000e+00, float 7.000000e+00, float 8.000000e+00]
 // CHECK: [16 x float] [float 2.500000e+01, float 2.700000e+01, float 2.600000e+01, float 2.800000e+01, float 2.500000e+01, float 2.700000e+01, float 2.600000e+01, float 2.800000e+01, float 2.500000e+01, float 2.700000e+01, float 2.600000e+01, float 2.800000e+01, float 2.500000e+01, float 2.700000e+01, float 2.600000e+01, float 2.800000e+01]
 
 static float4 f0 = {5,6,7,8};

+ 4 - 5
tools/clang/test/HLSLFileCheck/shader_targets/hull/static_res_in_patch_constant_func2.hlsl

@@ -1,13 +1,12 @@
 // RUN: %dxc -E main -T hs_6_0  %s 2>&1 | FileCheck %s
 
-// Make sure @sf is restored to original value in patch constant function.
+// Make sure @sf is restored to original value 3.0 in patch constant function.
 // CHECK:define void @"\01?HSPerPatchFunc@@YA?AUHSPerPatchData@@XZ"() {
-// CHECK:store float 3.000000e+00, float* @sf, align 4
-// CHECK-NEXT:call void @dx.op.storePatchConstant.f32
-// CHECK-NEXT:call void @dx.op.storePatchConstant.f32
+
+// CHECK:call void @dx.op.storePatchConstant.f32
 // CHECK-NEXT:call void @dx.op.storePatchConstant.f32
-// CHECK-NEXT:load float, float* @sf, align 4
 // CHECK-NEXT:call void @dx.op.storePatchConstant.f32
+// CHECK-NEXT:call void @dx.op.storePatchConstant.f32(i32 106, i32 1, i32 0, i8 0, float 3.000000e+00)
 struct HSPerPatchData
 {
 	float	edges[3] : SV_TessFactor;