Browse Source

Lower static global resource and local resource to handle. (#276)

1. Add ResourceToHandle pass to lower resource to handle.
2. Don't performPromotion in SROA_HLSL.
3. Add Option support for DynamicIndexingVectorToArray.
4. Fix bug in GetPassOption.
5. Replace GEP ptr, 0 with ptr in DynamicIndexingVectorToArray::ReplaceStaticIndexingOnVector.
6. Run mem2reg before DxilGenerationPass.
7.Legalize EvalOperations before change vector to array.
Xiang Li 8 years ago
parent
commit
9edb1a553e

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

@@ -46,6 +46,7 @@ ModulePass *createDxilLoadMetadataPass();
 ModulePass *createDxilPrecisePropagatePass();
 FunctionPass *createDxilLegalizeResourceUsePass();
 ModulePass *createDxilLegalizeStaticResourceUsePass();
+ModulePass *createDxilLegalizeEvalOperationsPass();
 FunctionPass *createDxilLegalizeSampleOffsetPass();
 FunctionPass *createSimplifyInstPass();
 
@@ -58,6 +59,7 @@ void initializeDxilLoadMetadataPass(llvm::PassRegistry&);
 void initializeDxilPrecisePropagatePassPass(llvm::PassRegistry&);
 void initializeDxilLegalizeResourceUsePassPass(llvm::PassRegistry&);
 void initializeDxilLegalizeStaticResourceUsePassPass(llvm::PassRegistry&);
+void initializeDxilLegalizeEvalOperationsPass(llvm::PassRegistry&);
 void initializeDxilLegalizeSampleOffsetPassPass(llvm::PassRegistry&);
 void initializeSimplifyInstPass(llvm::PassRegistry&);
 

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

@@ -198,6 +198,7 @@ public:
   static unsigned
   GetLegacyCBufferFieldElementSize(DxilFieldAnnotation &fieldAnnotation,
                                    llvm::Type *Ty, DxilTypeSystem &typeSys);
+  static llvm::Type *GetArrayEltTy(llvm::Type *Ty);
 
   static bool IsStaticGlobal(llvm::GlobalVariable *GV);
   static bool IsSharedMemoryGlobal(llvm::GlobalVariable *GV);

+ 1 - 0
include/llvm/InitializePasses.h

@@ -255,6 +255,7 @@ void initializeSROA_DT_HLSLPass(PassRegistry&);
 void initializeSROA_Parameter_HLSLPass(PassRegistry&);
 void initializeDynamicIndexingVectorToArrayPass(PassRegistry&);
 void initializeMultiDimArrayToOneDimArrayPass(PassRegistry&);
+void initializeResourceToHandlePass(PassRegistry&);
 void initializeSROA_SSAUp_HLSLPass(PassRegistry&);
 void initializeHoistConstantArrayPass(PassRegistry&);
 // HLSL Change Ends

+ 5 - 0
include/llvm/Transforms/Scalar.h

@@ -134,6 +134,11 @@ void initializeDynamicIndexingVectorToArrayPass(PassRegistry&);
 //
 ModulePass *createMultiDimArrayToOneDimArrayPass();
 void initializeMultiDimArrayToOneDimArrayPass(PassRegistry&);
+//===----------------------------------------------------------------------===//
+// Flatten resource into handle.
+//
+ModulePass *createResourceToHandlePass();
+void initializeResourceToHandlePass(PassRegistry&);
 
 //===----------------------------------------------------------------------===//
 // Hoist a local array initialized with constant values to a global array with

+ 4 - 2
lib/HLSL/DxcOptimizer.cpp

@@ -83,6 +83,7 @@ HRESULT SetupRegistryPassForHLSL() {
     initializeDxilCondenseResourcesPass(Registry);
     initializeDxilEmitMetadataPass(Registry);
     initializeDxilGenerationPassPass(Registry);
+    initializeDxilLegalizeEvalOperationsPass(Registry);
     initializeDxilLegalizeResourceUsePassPass(Registry);
     initializeDxilLegalizeSampleOffsetPassPass(Registry);
     initializeDxilLegalizeStaticResourceUsePassPass(Registry);
@@ -124,6 +125,7 @@ HRESULT SetupRegistryPassForHLSL() {
     initializeReassociatePass(Registry);
     initializeReducibilityAnalysisPass(Registry);
     initializeRegToMemHlslPass(Registry);
+    initializeResourceToHandlePass(Registry);
     initializeRewriteSymbolsPass(Registry);
     initializeSCCPPass(Registry);
     initializeSROAPass(Registry);
@@ -160,7 +162,7 @@ static ArrayRef<LPCSTR> GetPassArgNames(LPCSTR passName) {
   static const LPCSTR ArgPromotionArgs[] = { "maxElements" };
   static const LPCSTR CFGSimplifyPassArgs[] = { "Threshold", "Ftor", "bonus-inst-threshold" };
   static const LPCSTR DxilGenerationPassArgs[] = { "NotOptimized" };
-  static const LPCSTR DynamicIndexingVectorToArrayArgs[] = { "ReplaceAllVector" };
+  static const LPCSTR DynamicIndexingVectorToArrayArgs[] = { "ReplaceAllVectors" };
   static const LPCSTR Float2IntArgs[] = { "float2int-max-integer-bw" };
   static const LPCSTR GVNArgs[] = { "noloads", "enable-pre", "enable-load-pre", "max-recurse-depth" };
   static const LPCSTR JumpThreadingArgs[] = { "Threshold", "jump-threading-threshold" };
@@ -296,7 +298,7 @@ static bool IsPassOptionName(StringRef S) {
     ||  S.equals("MaxHeaderSize")
     ||  S.equals("NotOptimized")
     ||  S.equals("Os")
-    ||  S.equals("ReplaceAllVector")
+    ||  S.equals("ReplaceAllVectors")
     ||  S.equals("RequiresDomTree")
     ||  S.equals("Runtime")
     ||  S.equals("ScalarLoadThreshold")

+ 128 - 202
lib/HLSL/DxilGenerationPass.cpp

@@ -256,7 +256,6 @@ public:
     // Load up debug information, to cross-reference values and the instructions
     // used to load them.
     m_HasDbgInfo = getDebugMetadataVersionFromModule(M) != 0;
-    LegalizeEvalOperations(M);
     if (!SM->IsCS()) {
       CreateDxilSignatures();
 
@@ -381,10 +380,6 @@ private:
   // For validation
   std::unordered_map<unsigned, std::unordered_set<unsigned> > m_InputSemanticsUsed,
     m_OutputSemanticsUsed[4], m_PatchConstantSemanticsUsed, m_OtherSemanticsUsed;
-
-  // For EvaluateAttribute operations.
-  void LegalizeEvalOperations(Module &M);
-  void FindAllocasForEvalOperations(Value *f, std::unordered_set<AllocaInst*> &allocas);
 };
 
 class SimplifyInst : public FunctionPass {
@@ -2708,81 +2703,6 @@ void DxilGenerationPass::UpdateStructTypeForLegacyLayout() {
   UpdateStructTypeForLegacyLayoutOnHLM(*m_pHLModule);
 }
 
-// Find allocas for EvaluateAttribute operations
-void DxilGenerationPass::FindAllocasForEvalOperations(
-    Value *val, std::unordered_set<AllocaInst *> &allocas) {
-  Value *CurVal = val;
-  while (!isa<AllocaInst>(CurVal)) {
-    if (CallInst *CI = dyn_cast<CallInst>(CurVal)) {
-      CurVal = CI->getOperand(HLOperandIndex::kUnaryOpSrc0Idx);
-    } else if (InsertElementInst *IE = dyn_cast<InsertElementInst>(CurVal)) {
-      Value *arg0 =
-          IE->getOperand(0); // Could be another insertelement or undef
-      Value *arg1 = IE->getOperand(1);
-      FindAllocasForEvalOperations(arg0, allocas);
-      CurVal = arg1;
-    } else if (ShuffleVectorInst *SV = dyn_cast<ShuffleVectorInst>(CurVal)) {
-      Value *arg0 = SV->getOperand(0);
-      Value *arg1 = SV->getOperand(1);
-      FindAllocasForEvalOperations(
-          arg0, allocas); // Shuffle vector could come from different allocas
-      CurVal = arg1;
-    } else if (ExtractElementInst *EE = dyn_cast<ExtractElementInst>(CurVal)) {
-      CurVal = EE->getOperand(0);
-    } else if (LoadInst *LI = dyn_cast<LoadInst>(CurVal)) {
-      CurVal = LI->getOperand(0);
-    } else {
-      break;
-    }
-  }
-  if (AllocaInst *AI = dyn_cast<AllocaInst>(CurVal)) {
-    allocas.insert(AI);
-  }
-}
-
-// This is needed in order to translate EvaluateAttribute operations that traces
-// back to LoadInput operations during translation stage. Promoting load/store
-// instructions beforehand will allow us to easily trace back to loadInput from
-// function call.
-void DxilGenerationPass::LegalizeEvalOperations(Module &M) {
-  for (Function &F : M.getFunctionList()) {
-    hlsl::HLOpcodeGroup group = hlsl::GetHLOpcodeGroup(&F);
-    if (group != HLOpcodeGroup::NotHL) {
-      std::vector<CallInst *> EvalFunctionCalls;
-      // Find all EvaluateAttribute calls
-      for (User *U : F.users()) {
-        if (CallInst *CI = dyn_cast<CallInst>(U)) {
-          IntrinsicOp evalOp = static_cast<IntrinsicOp>(hlsl::GetHLOpcode(CI));
-          if (evalOp == IntrinsicOp::IOP_EvaluateAttributeAtSample ||
-            evalOp == IntrinsicOp::IOP_EvaluateAttributeCentroid ||
-            evalOp == IntrinsicOp::IOP_EvaluateAttributeSnapped) {
-            EvalFunctionCalls.push_back(CI);
-          }
-        }
-      }
-      if (EvalFunctionCalls.empty()) {
-        continue;
-      }
-      // Start from the call instruction, find all allocas that this call uses.
-      std::unordered_set<AllocaInst *> allocas;
-      for (CallInst *CI : EvalFunctionCalls) {
-        FindAllocasForEvalOperations(CI, allocas);
-      }
-      SSAUpdater SSA;
-      SmallVector<Instruction *, 4> Insts;
-      for (AllocaInst *AI : allocas) {
-        for (User *user : AI->users()) {
-          if (isa<LoadInst>(user) || isa<StoreInst>(user)) {
-            Insts.emplace_back(cast<Instruction>(user));
-          }
-        }
-        LoadAndStorePromoter(Insts, SSA).run(Insts);
-        Insts.clear();
-      }
-    }
-  }
-}
-
 ///////////////////////////////////////////////////////////////////////////////
 
 namespace {
@@ -3248,6 +3168,9 @@ public:
   }
 
   bool runOnModule(Module &M) override {
+    HLModule &HLM = M.GetOrCreateHLModule();
+    OP *hlslOP = HLM.GetOP();
+    Type *HandleTy = hlslOP->GetHandleType();
     // Promote static global variables.
     PromoteStaticGlobalResources(M);
 
@@ -3266,15 +3189,20 @@ public:
       }
     }
 
-    // Transform PHINode/SelectInst on resource into PHINode/SelectInst on
-    // Handle. This will make sure resource only have ld/st/gep use.
-    TransformResourcePHINodeToHandlePHINode(M);
+    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)) {
+          M.getContext().emitError(kResourceMapErrorMsg);
+        }
+      }
+    }
     return true;
   }
 
 private:
   void PromoteStaticGlobalResources(Module &M);
-  void TransformResourcePHINodeToHandlePHINode(Module &M);
   void TransformHandleCast(Function &F);
 };
 
@@ -3318,6 +3246,9 @@ void DxilLegalizeResourceUsePass::PromoteLocalResource(Function &F) {
   DominatorTree *DT = &getAnalysis<DominatorTreeWrapperPass>().getDomTree();
   AssumptionCache &AC =
       getAnalysis<AssumptionCacheTracker>().getAssumptionCache(F);
+  HLModule &HLM = F.getParent()->GetOrCreateHLModule();
+  OP *hlslOP = HLM.GetOP();
+  Type *HandleTy = hlslOP->GetHandleType();
 
   BasicBlock &BB = F.getEntryBlock();
   unsigned allocaSize = 0;
@@ -3328,7 +3259,7 @@ 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 (IsResourceType(AI->getAllocatedType()))
+        if (HandleTy == HLModule::GetArrayEltTy(AI->getAllocatedType()))
           Allocas.push_back(AI);
       }
     if (Allocas.empty())
@@ -3363,10 +3294,13 @@ INITIALIZE_PASS_END(DxilLegalizeResourceUsePass,
 
 void DxilLegalizeStaticResourceUsePass::PromoteStaticGlobalResources(
     Module &M) {
+  HLModule &HLM = M.GetOrCreateHLModule();
+  Type *HandleTy = HLM.GetOP()->GetHandleType();
+
   std::set<GlobalVariable *> staticResources;
   for (auto &GV : M.globals()) {
     if (GV.getLinkage() == GlobalValue::LinkageTypes::InternalLinkage &&
-        IsResourceType(GV.getType()->getElementType())) {
+        HandleTy == HLModule::GetArrayEltTy(GV.getType())) {
       staticResources.insert(&GV);
     }
   }
@@ -3398,122 +3332,6 @@ void DxilLegalizeStaticResourceUsePass::PromoteStaticGlobalResources(
   }
 }
 
-void DxilLegalizeStaticResourceUsePass::TransformResourcePHINodeToHandlePHINode(
-    Module &M) {
-  HLModule &HLM = M.GetOrCreateHLModule();
-  OP *hlslOP = HLM.GetOP();
-  Type *HandleTy = hlslOP->GetHandleType();
-
-  std::unordered_set<Instruction *> resSet;
-  // Find all hl create handle which use a phi/select.
-  for (Function &TempF : M.functions()) {
-    if (GetHLOpcodeGroupByName(&TempF) == HLOpcodeGroup::HLCreateHandle) {
-      for (User *U : TempF.users()) {
-        CallInst *CI = cast<CallInst>(U);
-        Value *ResOp =
-            CI->getArgOperand(HLOperandIndex::kCreateHandleResourceOpIdx);
-        if (Instruction *Res = dyn_cast<Instruction>(ResOp))
-          AddResourceToSet(Res, resSet);
-        else if (isa<UndefValue>(ResOp)) {
-          CI->getContext().emitError(CI, kResourceMapErrorMsg);
-          continue;
-        }
-      }
-    }
-  }
-
-  Value *UndefHandle = UndefValue::get(HandleTy);
-
-  // Generate Handle inst for Res inst.
-  std::unordered_map<Instruction *, Value *> resHandleMap;
-  for (Instruction *Res : resSet) {
-    unsigned numOperands = Res->getNumOperands();
-    IRBuilder<> Builder(Res);
-
-    unsigned startOpIdx = 0;
-    // Skip Cond for Select.
-    if (SelectInst *Sel = dyn_cast<SelectInst>(Res)) {
-      startOpIdx = 1;
-      Value *Cond = Sel->getCondition();
-      // Use undef handle to create, will be updated in next loop.
-      Value *Handle = Builder.CreateSelect(Cond, UndefHandle, UndefHandle);
-      resHandleMap[Res] = Handle;
-    } else {
-      PHINode *Phi = cast<PHINode>(Res);
-      PHINode *HandlePhi = Builder.CreatePHI(HandleTy, numOperands);
-      // Use undef handle to create, will be updated in next loop.
-      for (unsigned i = 0; i < numOperands; i++) {
-        BasicBlock *BB = Phi->getIncomingBlock(i);
-        HandlePhi->addIncoming(UndefHandle, BB);
-      }
-      resHandleMap[Res] = HandlePhi;
-    }
-
-    // Generate createHandle for LdInst opreands.
-    for (unsigned i = startOpIdx; i < numOperands; i++) {
-      if (LoadInst *LI = dyn_cast<LoadInst>(Res->getOperand(i))) {
-        if (resHandleMap.count(LI))
-          continue;
-        IRBuilder<> LocalBuilder(LI);
-
-        Instruction *Handle =
-            HLM.EmitHLOperationCall(LocalBuilder, HLOpcodeGroup::HLCreateHandle,
-                                    /*opcode*/ 0, HandleTy, {LI}, M);
-        // No new HL createHandle will be created.
-        // So don't need MarkResourceAttribute here.
-        resHandleMap[LI] = Handle;
-      }
-    }
-  }
-
-  // Update operand for Handle phi/select.
-  for (Instruction *Res : resSet) {
-    unsigned numOperands = Res->getNumOperands();
-
-    unsigned startOpIdx = 0;
-    // Skip Cond for Select.
-    if (SelectInst *Sel = dyn_cast<SelectInst>(Res))
-      startOpIdx = 1;
-
-    Instruction *Handle = cast<Instruction>(resHandleMap[Res]);
-
-    for (unsigned i = startOpIdx; i < numOperands; i++) {
-      if (!isa<Instruction>(Res->getOperand(i))) {
-        Res->getContext().emitError(Res, kResourceMapErrorMsg);
-        continue;
-      }
-      Instruction *ResOp = cast<Instruction>(Res->getOperand(i));
-      if (resHandleMap.count(ResOp) == 0) {
-        Res->getContext().emitError(Res, kResourceMapErrorMsg);
-        continue;
-      }
-      Instruction *HandleOp = cast<Instruction>(resHandleMap[ResOp]);
-      Handle->setOperand(i, HandleOp);
-    }
-  }
-
-  // Replace use of handle with new created handle.
-  for (Instruction *Res : resSet) {
-    Value *Handle = resHandleMap[Res];
-    for (auto U = Res->user_begin(); U != Res->user_end();) {
-      User *ResU = *(U++);
-      if (isa<CallInst>(ResU) && ResU->getType() == HandleTy) {
-        ResU->replaceAllUsesWith(Handle);
-        cast<Instruction>(ResU)->eraseFromParent();
-      }
-    }
-  }
-
-  // Remove the unused phi/select on resource.
-  for (Instruction *Res : resSet) {
-    Res->dropAllReferences();
-  }
-
-  for (Instruction *Res : resSet) {
-    Res->eraseFromParent();
-  }
-}
-
 static void ReplaceResUseWithHandle(Instruction *Res, Value *Handle) {
   Type *HandleTy = Handle->getType();
   for (auto ResU = Res->user_begin(); ResU != Res->user_end();) {
@@ -3551,3 +3369,111 @@ ModulePass *llvm::createDxilLegalizeStaticResourceUsePass() {
 INITIALIZE_PASS(DxilLegalizeStaticResourceUsePass,
                 "hlsl-dxil-legalize-static-resource-use",
                 "DXIL legalize static resource use", false, false)
+
+///////////////////////////////////////////////////////////////////////////////
+// Legalize EvalOperations.
+// Make sure src of EvalOperations are from function parameter.
+// This is needed in order to translate EvaluateAttribute operations that traces
+// back to LoadInput operations during translation stage. Promoting load/store
+// instructions beforehand will allow us to easily trace back to loadInput from
+// function call.
+namespace {
+
+class DxilLegalizeEvalOperations : public ModulePass {
+public:
+  static char ID; // Pass identification, replacement for typeid
+  explicit DxilLegalizeEvalOperations() : ModulePass(ID) {}
+
+  const char *getPassName() const override {
+    return "DXIL Legalize EvalOperations";
+  }
+
+  bool runOnModule(Module &M) override {
+    for (Function &F : M.getFunctionList()) {
+      hlsl::HLOpcodeGroup group = hlsl::GetHLOpcodeGroup(&F);
+      if (group != HLOpcodeGroup::NotHL) {
+        std::vector<CallInst *> EvalFunctionCalls;
+        // Find all EvaluateAttribute calls
+        for (User *U : F.users()) {
+          if (CallInst *CI = dyn_cast<CallInst>(U)) {
+            IntrinsicOp evalOp =
+                static_cast<IntrinsicOp>(hlsl::GetHLOpcode(CI));
+            if (evalOp == IntrinsicOp::IOP_EvaluateAttributeAtSample ||
+                evalOp == IntrinsicOp::IOP_EvaluateAttributeCentroid ||
+                evalOp == IntrinsicOp::IOP_EvaluateAttributeSnapped) {
+              EvalFunctionCalls.push_back(CI);
+            }
+          }
+        }
+        if (EvalFunctionCalls.empty()) {
+          continue;
+        }
+        // Start from the call instruction, find all allocas that this call
+        // uses.
+        std::unordered_set<AllocaInst *> allocas;
+        for (CallInst *CI : EvalFunctionCalls) {
+          FindAllocasForEvalOperations(CI, allocas);
+        }
+        SSAUpdater SSA;
+        SmallVector<Instruction *, 4> Insts;
+        for (AllocaInst *AI : allocas) {
+          for (User *user : AI->users()) {
+            if (isa<LoadInst>(user) || isa<StoreInst>(user)) {
+              Insts.emplace_back(cast<Instruction>(user));
+            }
+          }
+          LoadAndStorePromoter(Insts, SSA).run(Insts);
+          Insts.clear();
+        }
+      }
+    }
+    return true;
+  }
+
+private:
+  void FindAllocasForEvalOperations(Value *val,
+                                    std::unordered_set<AllocaInst *> &allocas);
+};
+
+char DxilLegalizeEvalOperations::ID = 0;
+
+// Find allocas for EvaluateAttribute operations
+void DxilLegalizeEvalOperations::FindAllocasForEvalOperations(
+    Value *val, std::unordered_set<AllocaInst *> &allocas) {
+  Value *CurVal = val;
+  while (!isa<AllocaInst>(CurVal)) {
+    if (CallInst *CI = dyn_cast<CallInst>(CurVal)) {
+      CurVal = CI->getOperand(HLOperandIndex::kUnaryOpSrc0Idx);
+    } else if (InsertElementInst *IE = dyn_cast<InsertElementInst>(CurVal)) {
+      Value *arg0 =
+          IE->getOperand(0); // Could be another insertelement or undef
+      Value *arg1 = IE->getOperand(1);
+      FindAllocasForEvalOperations(arg0, allocas);
+      CurVal = arg1;
+    } else if (ShuffleVectorInst *SV = dyn_cast<ShuffleVectorInst>(CurVal)) {
+      Value *arg0 = SV->getOperand(0);
+      Value *arg1 = SV->getOperand(1);
+      FindAllocasForEvalOperations(
+          arg0, allocas); // Shuffle vector could come from different allocas
+      CurVal = arg1;
+    } else if (ExtractElementInst *EE = dyn_cast<ExtractElementInst>(CurVal)) {
+      CurVal = EE->getOperand(0);
+    } else if (LoadInst *LI = dyn_cast<LoadInst>(CurVal)) {
+      CurVal = LI->getOperand(0);
+    } else {
+      break;
+    }
+  }
+  if (AllocaInst *AI = dyn_cast<AllocaInst>(CurVal)) {
+    allocas.insert(AI);
+  }
+}
+} // namespace
+
+ModulePass *llvm::createDxilLegalizeEvalOperationsPass() {
+  return new DxilLegalizeEvalOperations();
+}
+
+INITIALIZE_PASS(DxilLegalizeEvalOperations,
+                "hlsl-dxil-legalize-eval-operations",
+                "DXIL legalize eval operations", false, false)

+ 9 - 0
lib/HLSL/HLModule.cpp

@@ -874,6 +874,15 @@ bool HLModule::IsHLSLObjectType(llvm::Type *Ty) {
   return false;
 }
 
+Type *HLModule::GetArrayEltTy(Type *Ty) {
+  if (isa<PointerType>(Ty))
+    Ty = Ty->getPointerElementType();
+  while (isa<ArrayType>(Ty)) {
+    Ty = Ty->getArrayElementType();
+  }
+  return Ty;
+}
+
 unsigned
 HLModule::GetLegacyCBufferFieldElementSize(DxilFieldAnnotation &fieldAnnotation,
                                            llvm::Type *Ty,

+ 8 - 0
lib/HLSL/HLOperationLower.cpp

@@ -2339,6 +2339,10 @@ SampleHelper::SampleHelper(
   samplerHandle = CI->getArgOperand(kSamplerArgIndex);
 
   DXIL::ResourceKind RK = pObjHelper->GetRK(texHandle);
+  if (RK == DXIL::ResourceKind::Invalid) {
+    opcode = DXIL::OpCode::NumOpCodes;
+    return;
+  }
   unsigned coordDimensions = DxilResource::GetNumCoords(RK);
   unsigned offsetDimensions = DxilResource::GetNumOffsets(RK);
 
@@ -2676,6 +2680,10 @@ GatherHelper::GatherHelper(
   samplerHandle = CI->getArgOperand(kSamplerArgIndex);
 
   DXIL::ResourceKind RK = pObjHelper->GetRK(texHandle);
+  if (RK == DXIL::ResourceKind::Invalid) {
+    opcode = DXIL::OpCode::NumOpCodes;
+    return;
+  }
   unsigned coordSize = DxilResource::GetNumCoords(RK);
   unsigned offsetSize = DxilResource::GetNumOffsets(RK);
 

+ 4 - 4
lib/IR/Pass.cpp

@@ -320,7 +320,7 @@ bool llvm::GetPassOption(PassOptions &O, StringRef name, StringRef *pValue) {
 bool llvm::GetPassOptionBool(PassOptions &O, llvm::StringRef name, bool *pValue, bool defaultValue) {
   StringRef val;
   if (GetPassOption(O, name, &val)) {
-    *pValue = (name.startswith_lower("t") || name.equals("1"));
+    *pValue = (val.startswith_lower("t") || val.equals("1"));
     return true;
   }
   *pValue = defaultValue;
@@ -329,7 +329,7 @@ bool llvm::GetPassOptionBool(PassOptions &O, llvm::StringRef name, bool *pValue,
 bool llvm::GetPassOptionUnsigned(PassOptions &O, llvm::StringRef name, unsigned *pValue, unsigned defaultValue) {
   StringRef val;
   if (GetPassOption(O, name, &val)) {
-    name.getAsInteger<unsigned>(0, *pValue);
+    val.getAsInteger<unsigned>(0, *pValue);
     return true;
   }
   *pValue = defaultValue;
@@ -338,7 +338,7 @@ bool llvm::GetPassOptionUnsigned(PassOptions &O, llvm::StringRef name, unsigned
 bool llvm::GetPassOptionInt(PassOptions &O, llvm::StringRef name, int *pValue, int defaultValue) {
   StringRef val;
   if (GetPassOption(O, name, &val)) {
-    name.getAsInteger<int>(0, *pValue);
+    val.getAsInteger<int>(0, *pValue);
     return true;
   }
   *pValue = defaultValue;
@@ -347,7 +347,7 @@ bool llvm::GetPassOptionInt(PassOptions &O, llvm::StringRef name, int *pValue, i
 bool llvm::GetPassOptionUInt32(PassOptions &O, llvm::StringRef name, uint32_t *pValue, uint32_t defaultValue) {
   StringRef val;
   if (GetPassOption(O, name, &val)) {
-    name.getAsInteger<uint32_t>(0, *pValue);
+    val.getAsInteger<uint32_t>(0, *pValue);
     return true;
   }
   *pValue = defaultValue;

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

@@ -202,13 +202,25 @@ static void addHLSLPasses(bool HLSLHighLevel, bool NoOpt, hlsl::HLSLExtensionsCo
                                              /*Promote*/ !NoOpt));
 
   MPM.add(createHLMatrixLowerPass());
+  MPM.add(createResourceToHandlePass());
   // DCE should after SROA to remove unused element.
   MPM.add(createDeadCodeEliminationPass());
   MPM.add(createGlobalDCEPass());
 
+  if (NoOpt) {
+    // If not run mem2reg, try to promote allocas used by EvalOperations.
+    // Do this before change vector to array.
+    MPM.add(createDxilLegalizeEvalOperationsPass());
+  }
+
   // Change dynamic indexing vector to array.
   MPM.add(createDynamicIndexingVectorToArrayPass(NoOpt));
 
+  if (!NoOpt) {
+    // mem2reg
+    MPM.add(createPromoteMemoryToRegisterPass());
+  }
+
   MPM.add(createSimplifyInstPass());
   MPM.add(createCFGSimplificationPass());
 
@@ -219,11 +231,6 @@ static void addHLSLPasses(bool HLSLHighLevel, bool NoOpt, hlsl::HLSLExtensionsCo
 
   MPM.add(createSimplifyInstPass());
 
-  if (!NoOpt) {
-    // mem2reg
-    MPM.add(createPromoteMemoryToRegisterPass());
-  }
-
   // Propagate precise attribute.
   MPM.add(createDxilPrecisePropagatePass());
 

+ 190 - 15
lib/Transforms/Scalar/ScalarReplAggregatesHLSL.cpp

@@ -1071,7 +1071,6 @@ bool SROA_HLSL::runOnFunction(Function &F) {
   splitter.Split(F);
 
   Changed |= markPrecise(F);
-  Changed |= performPromotion(F);
 
   return Changed;
 }
@@ -2572,21 +2571,12 @@ void SROA_Helper::RewriteForGEP(GEPOperator *GEP, IRBuilder<> &Builder) {
   }
 }
 
-static Type *GetArrayEltTy(Type *Ty) {
-  if (isa<PointerType>(Ty))
-    Ty = Ty->getPointerElementType();
-  while (isa<ArrayType>(Ty)) {
-    Ty = Ty->getArrayElementType();
-  }
-  return Ty;
-}
-
 /// isVectorOrStructArray - Check if T is array of vector or struct.
 static bool isVectorOrStructArray(Type *T) {
   if (!T->isArrayTy())
     return false;
 
-  T = GetArrayEltTy(T);
+  T = HLModule::GetArrayEltTy(T);
 
   return T->isStructTy() || T->isVectorTy();
 }
@@ -4620,8 +4610,8 @@ void SROA_Parameter_HLSL::replaceCastParameter(
       }
     }
 
-    Type *NewEltTy = GetArrayEltTy(NewTy);
-    Type *OldEltTy = GetArrayEltTy(OldTy);
+    Type *NewEltTy = HLModule::GetArrayEltTy(NewTy);
+    Type *OldEltTy = HLModule::GetArrayEltTy(OldTy);
 
     if (NewEltTy == HandlePtrTy) {
       // Save resource attribute.
@@ -4924,7 +4914,7 @@ void SROA_Parameter_HLSL::flattenArgument(
           EltAnnotation.SetSemanticString(semantic);
         } else if (!eltSem.empty() &&
                  semanticTypeMap.count(eltSem) == 0) {
-          Type *EltTy = GetArrayEltTy(Ty);
+          Type *EltTy = HLModule::GetArrayEltTy(Ty);
           DXASSERT(EltTy->isStructTy(), "must be a struct type to has semantic.");
           semanticTypeMap[eltSem] = EltTy->getStructElementType(i);
         }
@@ -5863,6 +5853,7 @@ protected:
   virtual Type *lowerType(Type *Ty) = 0;
   virtual Constant *lowerInitVal(Constant *InitVal, Type *NewTy) = 0;
   virtual StringRef getGlobalPrefix() = 0;
+  virtual void initialize(Module &M) {};
 };
 
 AllocaInst *LowerTypePass::lowerAlloca(AllocaInst *A) {
@@ -5932,6 +5923,7 @@ bool LowerTypePass::runOnFunction(Function &F, bool HasDbgInfo) {
 }
 
 bool LowerTypePass::runOnModule(Module &M) {
+  initialize(M);
   // Load up debug information, to cross-reference values and the instructions
   // used to load them.
   bool HasDbgInfo = getDebugMetadataVersionFromModule(M) != 0;
@@ -5986,6 +5978,8 @@ public:
   explicit DynamicIndexingVectorToArray(bool ReplaceAll = false)
       : LowerTypePass(ID), ReplaceAllVectors(ReplaceAll) {}
   static char ID; // Pass identification, replacement for typeid
+  void applyOptions(PassOptions O) override;
+  void dumpConfig(raw_ostream &OS) override;
 protected:
   bool needToLower(Value *V) override;
   void lowerUseWithNewValue(Value *V, Value *NewV) override;
@@ -6004,6 +5998,15 @@ private:
   void ReplaceStaticIndexingOnVector(Value *V);
 };
 
+void DynamicIndexingVectorToArray::applyOptions(PassOptions O) {
+  GetPassOptionBool(O, "ReplaceAllVectors", &ReplaceAllVectors,
+                    ReplaceAllVectors);
+}
+void DynamicIndexingVectorToArray::dumpConfig(raw_ostream &OS) {
+  ModulePass::dumpConfig(OS);
+  OS << ",ReplaceAllVectors=" << ReplaceAllVectors;
+}
+
 void DynamicIndexingVectorToArray::ReplaceStaticIndexingOnVector(Value *V) {
   for (auto U = V->user_begin(), E = V->user_end(); U != E;) {
     Value *User = *(U++);
@@ -6048,6 +6051,14 @@ void DynamicIndexingVectorToArray::ReplaceStaticIndexingOnVector(Value *V) {
           }
         }
         GEP->eraseFromParent();
+      } else if (GEP->getNumIndices() == 1) {
+        Value *Idx = *GEP->idx_begin();
+        if (ConstantInt *C = dyn_cast<ConstantInt>(Idx)) {
+          if (C->getLimitedValue() == 0) {
+            GEP->replaceAllUsesWith(V);
+            GEP->eraseFromParent();
+          }
+        }
       }
     }
   }
@@ -6071,7 +6082,7 @@ bool DynamicIndexingVectorToArray::needToLower(Value *V) {
     // Array must be replaced even without dynamic indexing to remove vector
     // type in dxil.
     // TODO: optimize static array index in later pass.
-    Type *EltTy = GetArrayEltTy(AT);
+    Type *EltTy = HLModule::GetArrayEltTy(AT);
     return isa<VectorType>(EltTy);
   }
   return false;
@@ -6394,4 +6405,168 @@ INITIALIZE_PASS(MultiDimArrayToOneDimArray, "multi-dim-one-dim",
 // Public interface to the SROA_Parameter_HLSL pass
 ModulePass *llvm::createMultiDimArrayToOneDimArrayPass() {
   return new MultiDimArrayToOneDimArray();
+}
+
+//===----------------------------------------------------------------------===//
+// Lower resource into handle.
+//===----------------------------------------------------------------------===//
+
+namespace {
+
+class ResourceToHandle : public LowerTypePass {
+public:
+  explicit ResourceToHandle() : LowerTypePass(ID) {}
+  static char ID; // Pass identification, replacement for typeid
+protected:
+  bool needToLower(Value *V) override;
+  void lowerUseWithNewValue(Value *V, Value *NewV) override;
+  Type *lowerType(Type *Ty) override;
+  Constant *lowerInitVal(Constant *InitVal, Type *NewTy) override;
+  StringRef getGlobalPrefix() override { return ".res"; }
+  void initialize(Module &M) override;
+private:
+  void ReplaceResourceWithHandle(Value *ResPtr, Value *HandlePtr);
+  void ReplaceResourceGEPWithHandleGEP(Value *GEP, ArrayRef<Value *> idxList,
+                                       Value *A, IRBuilder<> &Builder);
+  void ReplaceResourceArrayWithHandleArray(Value *VA, Value *A);
+
+  Type *m_HandleTy;
+  HLModule *m_pHLM;
+};
+
+void ResourceToHandle::initialize(Module &M) {
+  DXASSERT(M.HasHLModule(), "require HLModule");
+  m_pHLM = &M.GetHLModule();
+  m_HandleTy = m_pHLM->GetOP()->GetHandleType();
+}
+
+bool ResourceToHandle::needToLower(Value *V) {
+  Type *Ty = V->getType()->getPointerElementType();
+  Ty = HLModule::GetArrayEltTy(Ty);
+  return (HLModule::IsHLSLObjectType(Ty) && !HLModule::IsStreamOutputType(Ty));
+}
+
+Type *ResourceToHandle::lowerType(Type *Ty) {
+  if ((HLModule::IsHLSLObjectType(Ty) && !HLModule::IsStreamOutputType(Ty))) {
+    return m_HandleTy;
+  }
+
+  ArrayType *AT = cast<ArrayType>(Ty);
+
+  SmallVector<ArrayType *, 4> nestArrayTys;
+  nestArrayTys.emplace_back(AT);
+
+  Type *EltTy = AT->getElementType();
+  // support multi level of array
+  while (EltTy->isArrayTy()) {
+    ArrayType *ElAT = cast<ArrayType>(EltTy);
+    nestArrayTys.emplace_back(ElAT);
+    EltTy = ElAT->getElementType();
+  }
+
+  return CreateNestArrayTy(m_HandleTy, nestArrayTys);
+}
+
+Constant *ResourceToHandle::lowerInitVal(Constant *InitVal, Type *NewTy) {
+  DXASSERT(isa<UndefValue>(InitVal), "resource cannot have real init val");
+  return UndefValue::get(NewTy);
+}
+
+void ResourceToHandle::ReplaceResourceWithHandle(Value *ResPtr,
+                                                 Value *HandlePtr) {
+  for (auto it = ResPtr->user_begin(); it != ResPtr->user_end();) {
+    User *U = *(it++);
+    if (LoadInst *LI = dyn_cast<LoadInst>(U)) {
+      IRBuilder<> Builder(LI);
+      Value *Handle = Builder.CreateLoad(HandlePtr);
+      Type *ResTy = LI->getType();
+      // Used by createHandle or Store.
+      for (auto ldIt = LI->user_begin(); ldIt != LI->user_end();) {
+        User *ldU = *(ldIt++);
+        if (StoreInst *SI = dyn_cast<StoreInst>(ldU)) {
+          Value *TmpRes = HLModule::EmitHLOperationCall(
+              Builder, HLOpcodeGroup::HLCast,
+              (unsigned)HLCastOpcode::HandleToResCast, ResTy, {Handle},
+              *m_pHLM->GetModule());
+          SI->replaceUsesOfWith(LI, TmpRes);
+        } else {
+          CallInst *CI = cast<CallInst>(ldU);
+          HLOpcodeGroup group =
+              hlsl::GetHLOpcodeGroupByName(CI->getCalledFunction());
+          DXASSERT(group == HLOpcodeGroup::HLCreateHandle,
+                   "must be createHandle");
+          CI->replaceAllUsesWith(Handle);
+          CI->eraseFromParent();
+        }
+      }
+      LI->eraseFromParent();
+    } else if (StoreInst *SI = dyn_cast<StoreInst>(U)) {
+      Value *Res = SI->getValueOperand();
+      IRBuilder<> Builder(SI);
+      // CreateHandle from Res.
+      Value *Handle = HLModule::EmitHLOperationCall(
+          Builder, HLOpcodeGroup::HLCreateHandle,
+          /*opcode*/ 0, m_HandleTy, {Res}, *m_pHLM->GetModule());
+      // Store Handle to HandlePtr.
+      Builder.CreateStore(Handle, HandlePtr);
+      // Remove resource Store.
+      SI->eraseFromParent();
+    } else {
+      DXASSERT(0, "invalid operation on resource");
+    }
+  }
+}
+
+void ResourceToHandle::ReplaceResourceGEPWithHandleGEP(
+    Value *GEP, ArrayRef<Value *> idxList, Value *A, IRBuilder<> &Builder) {
+  Value *newGEP = Builder.CreateGEP(A, idxList);
+  Type *Ty = GEP->getType()->getPointerElementType();
+  if (Ty->isArrayTy()) {
+    ReplaceResourceArrayWithHandleArray(GEP, newGEP);
+  } else {
+    DXASSERT(HLModule::IsHLSLObjectType(Ty), "must be resource type here");
+    ReplaceResourceWithHandle(GEP, newGEP);
+  }
+}
+
+void ResourceToHandle::ReplaceResourceArrayWithHandleArray(Value *VA,
+                                                           Value *A) {
+  for (auto U = VA->user_begin(); U != VA->user_end();) {
+    User *User = *(U++);
+    if (GetElementPtrInst *GEP = dyn_cast<GetElementPtrInst>(User)) {
+      IRBuilder<> Builder(GEP);
+      SmallVector<Value *, 4> idxList(GEP->idx_begin(), GEP->idx_end());
+      ReplaceResourceGEPWithHandleGEP(GEP, idxList, A, Builder);
+      GEP->eraseFromParent();
+    } else if (GEPOperator *GEPOp = dyn_cast<GEPOperator>(User)) {
+      IRBuilder<> Builder(GEPOp->getContext());
+      SmallVector<Value *, 4> idxList(GEPOp->idx_begin(), GEPOp->idx_end());
+      ReplaceResourceGEPWithHandleGEP(GEPOp, idxList, A, Builder);
+    } else {
+      DXASSERT(0, "Array pointer should only used by GEP");
+    }
+  }
+}
+
+void ResourceToHandle::lowerUseWithNewValue(Value *V, Value *NewV) {
+  Type *Ty = V->getType()->getPointerElementType();
+  // Replace V with NewV.
+  if (Ty->isArrayTy()) {
+    ReplaceResourceArrayWithHandleArray(V, NewV);
+  } else {
+    ReplaceResourceWithHandle(V, NewV);
+  }
+}
+
+}
+
+char ResourceToHandle::ID = 0;
+
+INITIALIZE_PASS(ResourceToHandle, "resource-handle",
+  "Lower resource into handle", false,
+  false)
+
+// Public interface to the ResourceToHandle pass
+ModulePass *llvm::createResourceToHandlePass() {
+  return new ResourceToHandle();
 }

+ 1 - 1
tools/clang/test/CodeGenHLSL/eval.hlsl

@@ -1,4 +1,4 @@
-// RUN: %dxc -E main -T ps_6_0 %s | FileCheck %s
+// RUN: %dxc -E main -T ps_6_0 -Od -Zi %s | FileCheck %s
 
 // CHECK: evalCentroid
 

+ 3 - 1
utils/hct/hctdb.py

@@ -1248,9 +1248,10 @@ class db_dxil(object):
         add_pass('die', 'DeadInstElimination', 'Dead Instruction Elimination', [])
         add_pass('globaldce', 'GlobalDCE', 'Dead Global Elimination', [])
         add_pass('dynamic-vector-to-array', 'DynamicIndexingVectorToArray', 'Replace dynamic indexing vector with array', [
-            {'n':'ReplaceAllVector','t':'ReplaceAllVector','c':1}])
+            {'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-legalize-eval-operations', 'DxilLegalizeEvalOperations', 'DXIL legalize eval operations', [])
         add_pass('dxilgen', 'DxilGenerationPass', 'HLSL DXIL Generation', [
             {'n':'NotOptimized','t':'bool','c':1}])
         add_pass('simplify-inst', 'SimplifyInst', 'Simplify Instructions', [])
@@ -1259,6 +1260,7 @@ class db_dxil(object):
         add_pass('dxil-legalize-sample-offset', 'DxilLegalizeSampleOffsetPass', 'DXIL legalize sample offset', [])
         add_pass('scalarizer', 'Scalarizer', 'Scalarize vector operations', [])
         add_pass('multi-dim-one-dim', 'MultiDimArrayToOneDimArray', 'Flatten multi-dim array into one-dim array', [])
+        add_pass('resource-handle', 'ResourceToHandle', 'Lower resource into handle', [])
         add_pass('hlsl-dxil-condense', 'DxilCondenseResources', 'DXIL Condense Resources', [])
         add_pass('hlsl-dxilemit', 'DxilEmitMetadata', 'HLSL DXIL Metadata Emit', [])
         add_pass('hlsl-dxilload', 'DxilLoadMetadata', 'HLSL DXIL Metadata Load', [])