浏览代码

Merged PR 10: Merge user/xiagli/non_uniform to user/texr/rt-merge-rebase

Xiang_Li (XBox) 7 年之前
父节点
当前提交
3c73c5bf29

+ 6 - 0
include/dxc/HLSL/DxilMetadataHelper.h

@@ -193,6 +193,9 @@ public:
   // Precise attribute.
   static const char kDxilPreciseAttributeMDName[];
 
+  // NonUniform attribute.
+  static const char kDxilNonUniformAttributeMDName[];
+
   // Validator version.
   static const char kDxilValidatorVersionMDName[];
   // Validator version uses the same constants for fields as kDxilVersion*
@@ -381,6 +384,7 @@ public:
 
   // Utility functions.
   static bool IsKnownNamedMetaData(llvm::NamedMDNode &Node);
+  static void combineDxilMetadata(llvm::Instruction *K, const llvm::Instruction *J);
   static llvm::ConstantAsMetadata *Int32ToConstMD(int32_t v, llvm::LLVMContext &Ctx);
   llvm::ConstantAsMetadata *Int32ToConstMD(int32_t v);
   static llvm::ConstantAsMetadata *Uint32ToConstMD(unsigned v, llvm::LLVMContext &Ctx);
@@ -405,6 +409,8 @@ public:
   void ConstMDTupleToUint32Vector(llvm::MDTuple *pTupleMD, std::vector<unsigned> &Vec);
   static bool IsMarkedPrecise(const llvm::Instruction *inst);
   static void MarkPrecise(llvm::Instruction *inst);
+  static bool IsMarkedNonUniform(const llvm::Instruction *inst);
+  static void MarkNonUniform(llvm::Instruction *inst);
 
 private:
   llvm::LLVMContext &m_Ctx;

+ 9 - 8
lib/HLSL/DxilCondenseResources.cpp

@@ -769,8 +769,7 @@ void DxilLowerCreateHandleForLib::TranslateDxilResourceUses(
   Value *resIDArg = hlslOP->GetU32Const(res.GetID());
   // resLowerBound will be added after allocation in DxilCondenseResources.
   Value *resLowerBound = hlslOP->GetU32Const(res.GetLowerBound());
-  // TODO: Set Non-uniform resource bit based on whether index comes from
-  // IOP_NonUniformResourceIndex.
+
   Value *isUniformRes = hlslOP->GetI1Const(0);
 
   Value *GV = res.GetGlobalSymbol();
@@ -851,16 +850,18 @@ void DxilLowerCreateHandleForLib::TranslateDxilResourceUses(
       }
 
       createHandleArgs[DXIL::OperandIndex::kCreateHandleResIndexOpIdx] = idx;
-      //if (!NonUniformSet.count(idx))
-      //  createHandleArgs[DXIL::OperandIndex::kCreateHandleIsUniformOpIdx] =
-      //      isUniformRes;
-      //else
-      //  createHandleArgs[DXIL::OperandIndex::kCreateHandleIsUniformOpIdx] =
-      //      hlslOP->GetI1Const(1);
+
+      createHandleArgs[DXIL::OperandIndex::kCreateHandleIsUniformOpIdx] =
+          isUniformRes;
 
       Value *handle = nullptr;
       if (GetElementPtrInst *GEPInst = dyn_cast<GetElementPtrInst>(GEP)) {
         IRBuilder<> Builder = IRBuilder<>(GEPInst);
+        if (DxilMDHelper::IsMarkedNonUniform(GEPInst)) {
+          // Mark nonUniform.
+          createHandleArgs[DXIL::OperandIndex::kCreateHandleIsUniformOpIdx] =
+              hlslOP->GetI1Const(1);
+        }
         createHandleArgs[DXIL::OperandIndex::kCreateHandleResIndexOpIdx] =
             Builder.CreateAdd(idx, resLowerBound);
         handle = Builder.CreateCall(createHandle, createHandleArgs, handleName);

+ 13 - 572
lib/HLSL/DxilGenerationPass.cpp

@@ -270,6 +270,7 @@ public:
     GenerateDxilCBufferHandles(NonUniformSet);
     MarkUpdateCounter(UpdateCounterSet);
     LowerHLCreateHandle();
+    MarkNonUniform(NonUniformSet);
 
     // For module which not promote mem2reg.
     // Remove local resource alloca/load/store/phi.
@@ -314,14 +315,6 @@ public:
 private:
   void RemoveLocalDxilResourceAllocas(Function *F);
   void MarkUpdateCounter(std::unordered_set<LoadInst *> &UpdateCounterSet);
-  void
-  TranslateDxilResourceUses(DxilResourceBase &res,
-                            std::unordered_set<LoadInst *> &UpdateCounterSet,
-                            std::unordered_set<Value *> &NonUniformSet);
-  void
-  GenerateDxilResourceHandles(std::unordered_set<LoadInst *> &UpdateCounterSet,
-                              std::unordered_set<Value *> &NonUniformSet);
-  void AddCreateHandleForPhiNodeAndSelect(OP *hlslOP);
   void TranslateParamDxilResourceHandles(Function *F, std::unordered_map<Instruction *, Value *> &handleMap);
   void GenerateParamDxilResourceHandles(
       std::unordered_map<Instruction *, Value *> &handleMap);
@@ -334,8 +327,7 @@ private:
                               std::unordered_set<LoadInst *> &UpdateCounterSet,
                               std::unordered_set<Value *> &NonUniformSet);
   void LowerHLCreateHandle();
-  // Change struct type to legacy layout for cbuf and struct buf.
-  void UpdateStructTypeForLegacyLayout();
+  void MarkNonUniform(std::unordered_set<Value *> &NonUniformSet);
 
   // Translate precise attribute into HL function call.
   void TranslatePreciseAttribute();
@@ -395,6 +387,17 @@ void DxilGenerationPass::LowerHLCreateHandle() {
   }
 }
 
+void DxilGenerationPass::MarkNonUniform(
+    std::unordered_set<Value *> &NonUniformSet) {
+  for (Value *V : NonUniformSet) {
+    for (User *U : V->users()) {
+      if (Instruction *I = dyn_cast<Instruction>(U)) {
+        DxilMDHelper::MarkNonUniform(I);
+      }
+    }
+  }
+}
+
 static Value *MergeImmResClass(Value *resClass) {
   if (ConstantInt *Imm = dyn_cast<ConstantInt>(resClass)) {
     return resClass;
@@ -603,403 +606,6 @@ void DxilGenerationPass::MarkUpdateCounter(
   }
 }
 
-void DxilGenerationPass::TranslateDxilResourceUses(
-    DxilResourceBase &res, std::unordered_set<LoadInst *> &UpdateCounterSet,
-    std::unordered_set<Value *> &NonUniformSet) {
-  OP *hlslOP = m_pHLModule->GetOP();
-  Function *createHandle = hlslOP->GetOpFunc(
-      OP::OpCode::CreateHandle, llvm::Type::getVoidTy(m_pHLModule->GetCtx()));
-  Value *opArg = hlslOP->GetU32Const((unsigned)OP::OpCode::CreateHandle);
-  bool isViewResource = res.GetClass() == DXIL::ResourceClass::SRV || res.GetClass() == DXIL::ResourceClass::UAV;
-  bool isROV = isViewResource && static_cast<DxilResource &>(res).IsROV();
-  std::string handleName = (res.GetGlobalName() + Twine("_") + Twine(res.GetResClassName())).str();
-  if (isViewResource)
-    handleName += (Twine("_") + Twine(res.GetResDimName())).str();
-  if (isROV)
-    handleName += "_ROV";
-
-  Value *resClassArg = hlslOP->GetU8Const(
-      static_cast<std::underlying_type<DxilResourceBase::Class>::type>(
-          res.GetClass()));
-  Value *resIDArg = hlslOP->GetU32Const(res.GetID());
-  // resLowerBound will be added after allocation in DxilCondenseResources.
-  Value *resLowerBound = hlslOP->GetU32Const(0);
-  // TODO: Set Non-uniform resource bit based on whether index comes from IOP_NonUniformResourceIndex.
-  Value *isUniformRes = hlslOP->GetI1Const(0);
-
-  Value *GV = res.GetGlobalSymbol();
-  Module *pM = m_pHLModule->GetModule();
-  // TODO: add debug info to create handle.
-  DIVariable *DIV = nullptr;
-  DILocation *DL = nullptr;
-  if (m_HasDbgInfo) {
-    DebugInfoFinder &Finder = m_pHLModule->GetOrCreateDebugInfoFinder();
-    DIV =
-        HLModule::FindGlobalVariableDebugInfo(cast<GlobalVariable>(GV), Finder);
-    if (DIV)
-      // TODO: how to get col?
-      DL =
-          DILocation::get(pM->getContext(), DIV->getLine(), 1, DIV->getScope());
-  }
-
-  bool isResArray = res.GetRangeSize() > 1;
-  std::unordered_map<Function *, Instruction *> handleMapOnFunction;
-
-  Value *createHandleArgs[] = {opArg, resClassArg, resIDArg, resLowerBound,
-                               isUniformRes};
-
-  for (iplist<Function>::iterator F : pM->getFunctionList()) {
-    if (!F->isDeclaration()) {
-      if (!isResArray) {
-        IRBuilder<> Builder(F->getEntryBlock().getFirstInsertionPt());
-        if (m_HasDbgInfo) {
-          // TODO: set debug info.
-          //Builder.SetCurrentDebugLocation(DL);
-        }
-        handleMapOnFunction[F] = Builder.CreateCall(createHandle, createHandleArgs, handleName);
-      }
-    }
-  }
-
-  for (auto U = GV->user_begin(), E = GV->user_end(); U != E; ) {
-    User *user = *(U++);
-    // Skip unused user.
-    if (user->user_empty())
-      continue;
-
-    if (LoadInst *ldInst = dyn_cast<LoadInst>(user)) {
-      if (UpdateCounterSet.count(ldInst)) {
-        DxilResource *resource = llvm::dyn_cast<DxilResource>(&res);
-        DXASSERT_NOMSG(resource);
-        DXASSERT_NOMSG(resource->GetClass() == DXIL::ResourceClass::UAV);
-        resource->SetHasCounter(true);
-      }
-      Function *userF = ldInst->getParent()->getParent();
-      DXASSERT(handleMapOnFunction.count(userF), "must exist");
-      Value *handle = handleMapOnFunction[userF];
-      ReplaceResourceUserWithHandle(ldInst, handle);
-    } 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);
-      Value *idx = nullptr;
-      if (GEP->getNumIndices() == 2) {
-        // one dim array of resource
-        idx = (GEP->idx_begin() + 1)->get();
-      } else {
-        gep_type_iterator GEPIt = gep_type_begin(GEP), E = gep_type_end(GEP);
-        // Must be instruction for multi dim array.
-        std::unique_ptr<IRBuilder<> > Builder;
-        if (GetElementPtrInst *GEPInst = dyn_cast<GetElementPtrInst>(GEP)) {
-          Builder = std::make_unique<IRBuilder<> >(GEPInst);
-        } else {
-          Builder = std::make_unique<IRBuilder<> >(GV->getContext());
-        }
-        for (; GEPIt != E; ++GEPIt) {
-          if (GEPIt->isArrayTy()) {
-            unsigned arraySize = GEPIt->getArrayNumElements();
-            Value * tmpIdx = GEPIt.getOperand();
-            if (idx == nullptr)
-              idx = tmpIdx;
-            else {
-              idx = Builder->CreateMul(idx, Builder->getInt32(arraySize));
-              idx = Builder->CreateAdd(idx, tmpIdx);
-            }
-          }
-        }
-      }
-
-      createHandleArgs[DXIL::OperandIndex::kCreateHandleResIndexOpIdx] = idx;
-      if (!NonUniformSet.count(idx))
-        createHandleArgs[DXIL::OperandIndex::kCreateHandleIsUniformOpIdx] =
-            isUniformRes;
-      else
-        createHandleArgs[DXIL::OperandIndex::kCreateHandleIsUniformOpIdx] =
-            hlslOP->GetI1Const(1);
-
-      Value *handle = nullptr;
-      if (GetElementPtrInst *GEPInst = dyn_cast<GetElementPtrInst>(GEP)) {
-        IRBuilder<> Builder = IRBuilder<>(GEPInst);
-        handle = Builder.CreateCall(createHandle, createHandleArgs, handleName);
-      }
-
-      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)) {
-          DxilResource *resource = dyn_cast<DxilResource>(&res);
-          DXASSERT_NOMSG(resource);
-          DXASSERT_NOMSG(resource->GetClass() == DXIL::ResourceClass::UAV);
-          resource->SetHasCounter(true);
-        }
-        if (handle) {
-          ReplaceResourceUserWithHandle(ldInst, handle);
-        }
-        else {
-          IRBuilder<> Builder = IRBuilder<>(ldInst);
-          Value *localHandle = Builder.CreateCall(createHandle, createHandleArgs, handleName);
-          ReplaceResourceUserWithHandle(ldInst, localHandle);
-        }
-      }
-    }
-  }
-  // Erase unused handle.
-  for (auto It : handleMapOnFunction) {
-    Instruction *I = It.second;
-    if (I->user_empty())
-      I->eraseFromParent();
-  }
-}
-
-void DxilGenerationPass::GenerateDxilResourceHandles(
-    std::unordered_set<LoadInst *> &UpdateCounterSet,
-    std::unordered_set<Value *> &NonUniformSet) {
-  // Create sampler handle first, may be used by SRV operations.
-  for (size_t i = 0; i < m_pHLModule->GetSamplers().size(); i++) {
-    DxilSampler &S = m_pHLModule->GetSampler(i);
-    TranslateDxilResourceUses(S, UpdateCounterSet, NonUniformSet);
-  }
-
-  for (size_t i = 0; i < m_pHLModule->GetSRVs().size(); i++) {
-    HLResource &SRV = m_pHLModule->GetSRV(i);
-    TranslateDxilResourceUses(SRV, UpdateCounterSet, NonUniformSet);
-  }
-
-  for (size_t i = 0; i < m_pHLModule->GetUAVs().size(); i++) {
-    HLResource &UAV = m_pHLModule->GetUAV(i);
-    TranslateDxilResourceUses(UAV, UpdateCounterSet, NonUniformSet);
-  }
-}
-
-static void
-AddResourceToSet(Instruction *Res, std::unordered_set<Instruction *> &resSet) {
-  unsigned startOpIdx = 0;
-  // Skip Cond for Select.
-  if (isa<SelectInst>(Res))
-    startOpIdx = 1;
-  else if (!isa<PHINode>(Res))
-    // Only check phi and select here.
-    return;
-
-  // Already add.
-  if (resSet.count(Res))
-    return;
-
-  resSet.insert(Res);
-
-  // Scan operand to add resource node which only used by phi/select.
-  unsigned numOperands = Res->getNumOperands();
-  for (unsigned i = startOpIdx; i < numOperands; i++) {
-    Value *V = Res->getOperand(i);
-    if (Instruction *I = dyn_cast<Instruction>(V)) {
-      AddResourceToSet(I, resSet);
-    }
-  }
-}
-
-// Transform
-//
-//  %g_texture_texture_2d1 = call %dx.types.Handle @dx.op.createHandle(i32 57, i8 0, i32 0, i32 0, i1 false)
-//  %g_texture_texture_2d = call %dx.types.Handle @dx.op.createHandle(i32 57, i8 0, i32 0, i32 2, i1 false)
-//  %13 = select i1 %cmp, %dx.types.Handle %g_texture_texture_2d1, %dx.types.Handle %g_texture_texture_2d
-// Into
-//  %11 = select i1 %cmp, i32 0, i32 2
-//  %12 = call %dx.types.Handle @dx.op.createHandle(i32 57, i8 0, i32 0, i32 %11, i1 false)
-//
-
-static bool MergeHandleOpWithSameValue(Instruction *HandleOp,
-                                       unsigned startOpIdx,
-                                       unsigned numOperands) {
-  Value *op0 = nullptr;
-  for (unsigned i = startOpIdx; i < numOperands; i++) {
-    Value *op = HandleOp->getOperand(i);
-    if (i == startOpIdx) {
-      op0 = op;
-    } else {
-      if (op0 != op)
-        op0 = nullptr;
-    }
-  }
-  if (op0) {
-    HandleOp->replaceAllUsesWith(op0);
-    return true;
-  }
-  return false;
-}
-
-static void
-UpdateHandleOperands(Instruction *Res,
-                     std::unordered_map<Instruction *, CallInst *> &handleMap,
-                     std::unordered_set<Instruction *> &nonUniformOps) {
-  unsigned numOperands = Res->getNumOperands();
-
-  unsigned startOpIdx = 0;
-  // Skip Cond for Select.
-  if (SelectInst *Sel = dyn_cast<SelectInst>(Res))
-    startOpIdx = 1;
-
-  CallInst *Handle = handleMap[Res];
-
-  Instruction *resClass = cast<Instruction>(
-      Handle->getArgOperand(DXIL::OperandIndex::kCreateHandleResClassOpIdx));
-  Instruction *resID = cast<Instruction>(
-      Handle->getArgOperand(DXIL::OperandIndex::kCreateHandleResIDOpIdx));
-  Instruction *resAddr = cast<Instruction>(
-      Handle->getArgOperand(DXIL::OperandIndex::kCreateHandleResIndexOpIdx));
-
-  for (unsigned i = startOpIdx; i < numOperands; i++) {
-    if (!isa<Instruction>(Res->getOperand(i))) {
-      EmitResMappingError(Res);
-      continue;
-    }
-    Instruction *ResOp = cast<Instruction>(Res->getOperand(i));
-    CallInst *HandleOp = dyn_cast<CallInst>(ResOp);
-
-    if (!HandleOp) {
-      if (handleMap.count(ResOp)) {
-        EmitResMappingError(Res);
-        continue;
-      }
-      HandleOp = handleMap[ResOp];
-    }
-
-    Value *resClassOp =
-        HandleOp->getArgOperand(DXIL::OperandIndex::kCreateHandleResClassOpIdx);
-    Value *resIDOp =
-        HandleOp->getArgOperand(DXIL::OperandIndex::kCreateHandleResIDOpIdx);
-    Value *resAddrOp =
-        HandleOp->getArgOperand(DXIL::OperandIndex::kCreateHandleResIndexOpIdx);
-
-    resClass->setOperand(i, resClassOp);
-    resID->setOperand(i, resIDOp);
-    resAddr->setOperand(i, resAddrOp);
-  }
-
-  if (!MergeHandleOpWithSameValue(resClass, startOpIdx, numOperands))
-    nonUniformOps.insert(resClass);
-  if (!MergeHandleOpWithSameValue(resID, startOpIdx, numOperands))
-    nonUniformOps.insert(resID);
-  MergeHandleOpWithSameValue(resAddr, startOpIdx, numOperands);
-}
-
-void DxilGenerationPass::AddCreateHandleForPhiNodeAndSelect(OP *hlslOP) {
-  Function *createHandle = hlslOP->GetOpFunc(
-      OP::OpCode::CreateHandle, llvm::Type::getVoidTy(hlslOP->GetCtx()));
-
-  std::unordered_set<PHINode *> objPhiList;
-  std::unordered_set<SelectInst *> objSelectList;
-  std::unordered_set<Instruction *> resSelectSet;
-  for (User *U : createHandle->users()) {
-    for (User *HandleU : U->users()) {
-      Instruction *I = cast<Instruction>(HandleU);
-      if (!isa<CallInst>(I))
-        AddResourceToSet(I, resSelectSet);
-    }
-  }
-
-  // Generate Handle inst for Res inst.
-  FunctionType *FT = createHandle->getFunctionType();
-  Value *opArg = hlslOP->GetU32Const((unsigned)OP::OpCode::CreateHandle);
-  Type *resClassTy =
-      FT->getParamType(DXIL::OperandIndex::kCreateHandleResClassOpIdx);
-  Type *resIDTy = FT->getParamType(DXIL::OperandIndex::kCreateHandleResIDOpIdx);
-  Type *resAddrTy =
-      FT->getParamType(DXIL::OperandIndex::kCreateHandleResIndexOpIdx);
-  Value *UndefResClass = UndefValue::get(resClassTy);
-  Value *UndefResID = UndefValue::get(resIDTy);
-  Value *UndefResAddr = UndefValue::get(resAddrTy);
-
-  // phi/select node resource is not uniform
-  Value *nonUniformRes = hlslOP->GetI1Const(1);
-  std::unordered_map<Instruction *, CallInst *> handleMap;
-  for (Instruction *Res : resSelectSet) {
-    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();
-
-      Value *resClassSel =
-          Builder.CreateSelect(Cond, UndefResClass, UndefResClass);
-      Value *resIDSel = Builder.CreateSelect(Cond, UndefResID, UndefResID);
-      Value *resAddrSel =
-          Builder.CreateSelect(Cond, UndefResAddr, UndefResAddr);
-
-      CallInst *HandleSel =
-          Builder.CreateCall(createHandle, {opArg, resClassSel, resIDSel,
-                                            resAddrSel, nonUniformRes});
-      handleMap[Res] = HandleSel;
-      Res->replaceAllUsesWith(HandleSel);
-    } else {
-      PHINode *Phi = cast<PHINode>(Res); // res class must be same.
-      PHINode *resClassPhi = Builder.CreatePHI(resClassTy, numOperands);
-      PHINode *resIDPhi = Builder.CreatePHI(resIDTy, numOperands);
-      PHINode *resAddrPhi = Builder.CreatePHI(resAddrTy, numOperands);
-      for (unsigned i = 0; i < numOperands; i++) {
-        BasicBlock *BB = Phi->getIncomingBlock(i);
-        resClassPhi->addIncoming(UndefResClass, BB);
-        resIDPhi->addIncoming(UndefResID, BB);
-        resAddrPhi->addIncoming(UndefResAddr, BB);
-      }
-      IRBuilder<> HandleBuilder(Phi->getParent()->getFirstNonPHI());
-      CallInst *HandlePhi =
-          HandleBuilder.CreateCall(createHandle, {opArg, resClassPhi, resIDPhi,
-                                                  resAddrPhi, nonUniformRes});
-      handleMap[Res] = HandlePhi;
-      Res->replaceAllUsesWith(HandlePhi);
-    }
-  }
-
-  // Update operand for Handle phi/select.
-  // If ResClass or ResID is phi/select, save to nonUniformOps.
-  std::unordered_set<Instruction *> nonUniformOps;
-  for (Instruction *Res : resSelectSet) {
-    UpdateHandleOperands(Res, handleMap, nonUniformOps);
-  }
-
-  bool bIsLib = m_pHLModule->GetShaderModel()->IsLib();
-
-  // ResClass and ResID must be uniform.
-  // Try to merge res class, res id into imm.
-  while (1) {
-    bool bUpdated = false;
-
-    for (auto It = nonUniformOps.begin(); It != nonUniformOps.end();) {
-      Instruction *I = *(It++);
-      unsigned numOperands = I->getNumOperands();
-
-      unsigned startOpIdx = 0;
-      // Skip Cond for Select.
-      if (SelectInst *Sel = dyn_cast<SelectInst>(I))
-        startOpIdx = 1;
-      if (MergeHandleOpWithSameValue(I, startOpIdx, numOperands)) {
-        nonUniformOps.erase(I);
-        bUpdated = true;
-      }
-    }
-
-    if (!bUpdated) {
-      if (!nonUniformOps.empty() && !bIsLib) {
-        for (Instruction *I : nonUniformOps) {
-          // Non uniform res class or res id.
-          EmitResMappingError(I);
-        }
-        return;
-      }
-      break;
-    }
-  }
-
-  // Remove useless select/phi.
-  for (Instruction *Res : resSelectSet) {
-    Res->eraseFromParent();
-  }
-}
-
 void DxilGenerationPass::GenerateDxilCBufferHandles(
     std::unordered_set<Value *> &NonUniformSet) {
   // For CBuffer, handle are mapped to HLCreateHandle.
@@ -1194,171 +800,6 @@ ModulePass *llvm::createDxilGenerationPass(bool NotOptimized, hlsl::HLSLExtensio
 
 INITIALIZE_PASS(DxilGenerationPass, "dxilgen", "HLSL DXIL Generation", false, false)
 
-///////////////////////////////////////////////////////////////////////////////
-
-namespace {
-
-StructType *UpdateStructTypeForLegacyLayout(StructType *ST, bool IsCBuf,
-                                            DxilTypeSystem &TypeSys, Module &M);
-
-Type *UpdateFieldTypeForLegacyLayout(Type *Ty, bool IsCBuf, DxilFieldAnnotation &annotation,
-                      DxilTypeSystem &TypeSys, Module &M) {
-  DXASSERT(!Ty->isPointerTy(), "struct field should not be a pointer");
-
-  if (Ty->isArrayTy()) {
-    Type *EltTy = Ty->getArrayElementType();
-    Type *UpdatedTy = UpdateFieldTypeForLegacyLayout(EltTy, IsCBuf, annotation, TypeSys, M);
-    if (EltTy == UpdatedTy)
-      return Ty;
-    else
-      return ArrayType::get(UpdatedTy, Ty->getArrayNumElements());
-  } else if (HLMatrixLower::IsMatrixType(Ty)) {
-    DXASSERT(annotation.HasMatrixAnnotation(), "must a matrix");
-    unsigned rows, cols;
-    Type *EltTy = HLMatrixLower::GetMatrixInfo(Ty, cols, rows);
-
-    // Get cols and rows from annotation.
-    const DxilMatrixAnnotation &matrix = annotation.GetMatrixAnnotation();
-    if (matrix.Orientation == MatrixOrientation::RowMajor) {
-      rows = matrix.Rows;
-      cols = matrix.Cols;
-    } else {
-      DXASSERT(matrix.Orientation == MatrixOrientation::ColumnMajor, "");
-      cols = matrix.Rows;
-      rows = matrix.Cols;
-    }
-    // CBuffer matrix must 4 * 4 bytes align.
-    if (IsCBuf)
-      cols = 4;
-
-    EltTy = UpdateFieldTypeForLegacyLayout(EltTy, IsCBuf, annotation, TypeSys, M);
-    Type *rowTy = VectorType::get(EltTy, cols);
-    return ArrayType::get(rowTy, rows);
-  } else if (StructType *ST = dyn_cast<StructType>(Ty)) {
-    return UpdateStructTypeForLegacyLayout(ST, IsCBuf, TypeSys, M);
-  } else if (Ty->isVectorTy()) {
-    Type *EltTy = Ty->getVectorElementType();
-    Type *UpdatedTy = UpdateFieldTypeForLegacyLayout(EltTy, IsCBuf, annotation, TypeSys, M);
-    if (EltTy == UpdatedTy)
-      return Ty;
-    else
-      return VectorType::get(UpdatedTy, Ty->getVectorNumElements());
-  } else {
-    Type *i32Ty = Type::getInt32Ty(Ty->getContext());
-    // Basic types.
-    if (Ty->isHalfTy()) {
-      return Type::getFloatTy(Ty->getContext());
-    } else if (IntegerType *ITy = dyn_cast<IntegerType>(Ty)) {
-      if (ITy->getBitWidth() < 32)
-        return i32Ty;
-      else
-        return Ty;
-    } else
-      return Ty;
-  }
-}
-
-StructType *UpdateStructTypeForLegacyLayout(StructType *ST, bool IsCBuf,
-                                            DxilTypeSystem &TypeSys, Module &M) {
-  bool bUpdated = false;
-  unsigned fieldsCount = ST->getNumElements();
-  std::vector<Type *> fieldTypes(fieldsCount);
-  DxilStructAnnotation *SA = TypeSys.GetStructAnnotation(ST);
-  DXASSERT(SA, "must have annotation for struct type");
-
-  for (unsigned i = 0; i < fieldsCount; i++) {
-    Type *EltTy = ST->getElementType(i);
-    Type *UpdatedTy =
-        UpdateFieldTypeForLegacyLayout(EltTy, IsCBuf, SA->GetFieldAnnotation(i), TypeSys, M);
-    fieldTypes[i] = UpdatedTy;
-    if (EltTy != UpdatedTy)
-      bUpdated = true;
-  }
-
-  if (!bUpdated) {
-    return ST;
-  } else {
-    std::string legacyName = "dx.alignment.legacy." + ST->getName().str();
-    if (StructType *legacyST = M.getTypeByName(legacyName))
-      return legacyST;
-
-    StructType *NewST = StructType::create(ST->getContext(), fieldTypes, legacyName);
-    DxilStructAnnotation *NewSA = TypeSys.AddStructAnnotation(NewST);
-    // Clone annotation.
-    *NewSA = *SA;
-    return NewST;
-  }
-}
-
-void UpdateStructTypeForLegacyLayout(DxilResourceBase &Res, DxilTypeSystem &TypeSys, Module &M) {
-  GlobalVariable *GV = cast<GlobalVariable>(Res.GetGlobalSymbol());
-  Type *Ty = GV->getType()->getPointerElementType();
-  bool IsResourceArray = Res.GetRangeSize() != 1;
-  if (IsResourceArray) {
-    // Support Array of struct buffer.
-    if (Ty->isArrayTy())
-      Ty = Ty->getArrayElementType();
-  }
-  StructType *ST = cast<StructType>(Ty);
-  if (ST->isOpaque()) {
-    DXASSERT(Res.GetClass() == DxilResourceBase::Class::CBuffer,
-             "Only cbuffer can have opaque struct.");
-    return;
-  }
-
-  Type *UpdatedST = UpdateStructTypeForLegacyLayout(ST, IsResourceArray, TypeSys, M);
-  if (ST != UpdatedST) {
-    Type *Ty = GV->getType()->getPointerElementType();
-    if (IsResourceArray) {
-      // Support Array of struct buffer.
-      if (Ty->isArrayTy()) {
-        UpdatedST = ArrayType::get(UpdatedST, Ty->getArrayNumElements());
-      }
-    }
-    GlobalVariable *NewGV = cast<GlobalVariable>(M.getOrInsertGlobal(GV->getName().str() + "_legacy", UpdatedST));
-    Res.SetGlobalSymbol(NewGV);
-    // Delete old GV.
-    for (auto UserIt = GV->user_begin(); UserIt != GV->user_end(); ) {
-      Value *User = *(UserIt++);
-      if (Instruction *I = dyn_cast<Instruction>(User)) {
-        if (!User->user_empty())
-          I->replaceAllUsesWith(UndefValue::get(I->getType()));
-
-        I->eraseFromParent();
-      } else {
-        ConstantExpr *CE = cast<ConstantExpr>(User);
-        if (!CE->user_empty())
-          CE->replaceAllUsesWith(UndefValue::get(CE->getType()));
-      }
-    }
-    GV->removeDeadConstantUsers();
-    GV->eraseFromParent();
-  }
-}
-
-void UpdateStructTypeForLegacyLayoutOnHLM(HLModule &HLM) {
-  DxilTypeSystem &TypeSys = HLM.GetTypeSystem();
-  Module &M = *HLM.GetModule();
-  for (auto &CBuf : HLM.GetCBuffers()) {
-    UpdateStructTypeForLegacyLayout(*CBuf.get(), TypeSys, M);
-  }
-
-  for (auto &UAV : HLM.GetUAVs()) {
-    if (UAV->GetKind() == DxilResourceBase::Kind::StructuredBuffer)
-      UpdateStructTypeForLegacyLayout(*UAV.get(), TypeSys, M);
-  }
-
-  for (auto &SRV : HLM.GetSRVs()) {
-    if (SRV->GetKind() == DxilResourceBase::Kind::StructuredBuffer)
-      UpdateStructTypeForLegacyLayout(*SRV.get(), TypeSys, M);
-  }
-}
-
-}
-
-void DxilGenerationPass::UpdateStructTypeForLegacyLayout() {
-  UpdateStructTypeForLegacyLayoutOnHLM(*m_pHLModule);
-}
 
 ///////////////////////////////////////////////////////////////////////////////
 

+ 27 - 0
lib/HLSL/DxilMetadataHelper.cpp

@@ -48,6 +48,7 @@ const char DxilMDHelper::kDxilTypeSystemMDName[]                      = "dx.type
 const char DxilMDHelper::kDxilTypeSystemHelperVariablePrefix[]        = "dx.typevar.";
 const char DxilMDHelper::kDxilControlFlowHintMDName[]                 = "dx.controlflow.hints";
 const char DxilMDHelper::kDxilPreciseAttributeMDName[]                = "dx.precise";
+const char DxilMDHelper::kDxilNonUniformAttributeMDName[]             = "dx.nonuniform";
 const char DxilMDHelper::kHLDxilResourceAttributeMDName[]             = "dx.hl.resource.attribute";
 const char DxilMDHelper::kDxilValidatorVersionMDName[]                = "dx.valver";
 
@@ -1539,6 +1540,14 @@ bool DxilMDHelper::IsKnownNamedMetaData(llvm::NamedMDNode &Node) {
   return false;
 }
 
+void DxilMDHelper::combineDxilMetadata(llvm::Instruction *K,
+                                       const llvm::Instruction *J) {
+  if (IsMarkedNonUniform(J))
+    MarkNonUniform(K);
+  if (IsMarkedPrecise(J))
+    MarkPrecise(K);
+}
+
 ConstantAsMetadata *DxilMDHelper::Int32ToConstMD(int32_t v, LLVMContext &Ctx) {
   return ConstantAsMetadata::get(Constant::getIntegerValue(IntegerType::get(Ctx, 32), APInt(32, v)));
 }
@@ -1673,4 +1682,22 @@ void DxilMDHelper::MarkPrecise(Instruction *I) {
   I->setMetadata(DxilMDHelper::kDxilPreciseAttributeMDName, preciseNode);
 }
 
+bool DxilMDHelper::IsMarkedNonUniform(const Instruction *inst) {
+  int32_t val = 0;
+  if (MDNode *precise = inst->getMetadata(kDxilNonUniformAttributeMDName)) {
+    assert(precise->getNumOperands() == 1);
+    val = ConstMDToInt32(precise->getOperand(0));
+  }
+  return val;
+}
+
+void DxilMDHelper::MarkNonUniform(Instruction *I) {
+  LLVMContext &Ctx = I->getContext();
+  MDNode *preciseNode = MDNode::get(
+    Ctx,
+    { ConstantAsMetadata::get(ConstantInt::get(Type::getInt32Ty(Ctx), 1)) });
+
+  I->setMetadata(DxilMDHelper::kDxilNonUniformAttributeMDName, preciseNode);
+}
+
 } // namespace hlsl

+ 5 - 2
lib/HLSL/DxilValidation.cpp

@@ -358,6 +358,7 @@ struct ValidationContext {
   unsigned domainLocSize;
   const unsigned kDxilControlFlowHintMDKind;
   const unsigned kDxilPreciseMDKind;
+  const unsigned kDxilNonUniformMDKind;
   const unsigned kLLVMLoopMDKind;
   bool m_bCoverageIn, m_bInnerCoverageIn;
   unsigned m_DxilMajor, m_DxilMinor;
@@ -371,10 +372,11 @@ struct ValidationContext {
             DxilMDHelper::kDxilControlFlowHintMDName)),
         kDxilPreciseMDKind(llvmModule.getContext().getMDKindID(
             DxilMDHelper::kDxilPreciseAttributeMDName)),
+        kDxilNonUniformMDKind(llvmModule.getContext().getMDKindID(
+            DxilMDHelper::kDxilNonUniformAttributeMDName)),
         kLLVMLoopMDKind(llvmModule.getContext().getMDKindID("llvm.loop")),
         DiagPrinter(DiagPrn), LastRuleEmit((ValidationRule)-1),
-        m_bCoverageIn(false), m_bInnerCoverageIn(false),
-        hasViewID(false) {
+        m_bCoverageIn(false), m_bInnerCoverageIn(false), hasViewID(false) {
     DxilMod.GetDxilVersion(m_DxilMajor, m_DxilMinor);
     for (unsigned i = 0; i < DXIL::kNumOutputStreams; i++) {
       hasOutputPosition[i] = false;
@@ -2373,6 +2375,7 @@ static void ValidateInstructionMetadata(Instruction *I,
       }
     } else if (MD.first == ValCtx.kDxilPreciseMDKind) {
       // Validated in IsPrecise.
+    } else if (MD.first == ValCtx.kDxilNonUniformMDKind) {
     } else if (MD.first == ValCtx.kLLVMLoopMDKind) {
       ValidateLoopMetadata(MD.second, ValCtx);
     } else if (MD.first == LLVMContext::MD_tbaa) {

+ 6 - 0
lib/Transforms/Utils/Local.cpp

@@ -44,6 +44,8 @@
 #include "llvm/Support/Debug.h"
 #include "llvm/Support/MathExtras.h"
 #include "llvm/Support/raw_ostream.h"
+
+#include "dxc/HLSL/DxilMetadataHelper.h" // HLSL Change - combine dxil metadata.
 using namespace llvm;
 
 #define DEBUG_TYPE "local"
@@ -1323,6 +1325,10 @@ void llvm::combineMetadata(Instruction *K, const Instruction *J, ArrayRef<unsign
         break;
     }
   }
+
+  // HLSL Change Begin - combine dxil metadata.
+  hlsl::DxilMDHelper::combineDxilMetadata(K, J);
+  // HLSL Change End.
 }
 
 unsigned llvm::replaceDominatedUsesWith(Value *From, Value *To,

+ 4 - 4
tools/clang/test/CodeGenHLSL/selectObj4.hlsl

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