diff --git a/include/dxc/HLSL/DxilMetadataHelper.h b/include/dxc/HLSL/DxilMetadataHelper.h index e9d9b8dc1..4b95f3c58 100644 --- a/include/dxc/HLSL/DxilMetadataHelper.h +++ b/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 &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; diff --git a/lib/HLSL/DxilCondenseResources.cpp b/lib/HLSL/DxilCondenseResources.cpp index 4016a676d..eb3addcc2 100644 --- a/lib/HLSL/DxilCondenseResources.cpp +++ b/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(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); diff --git a/lib/HLSL/DxilGenerationPass.cpp b/lib/HLSL/DxilGenerationPass.cpp index e27359b07..e6aa0bd35 100644 --- a/lib/HLSL/DxilGenerationPass.cpp +++ b/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 &UpdateCounterSet); - void - TranslateDxilResourceUses(DxilResourceBase &res, - std::unordered_set &UpdateCounterSet, - std::unordered_set &NonUniformSet); - void - GenerateDxilResourceHandles(std::unordered_set &UpdateCounterSet, - std::unordered_set &NonUniformSet); - void AddCreateHandleForPhiNodeAndSelect(OP *hlslOP); void TranslateParamDxilResourceHandles(Function *F, std::unordered_map &handleMap); void GenerateParamDxilResourceHandles( std::unordered_map &handleMap); @@ -334,8 +327,7 @@ private: std::unordered_set &UpdateCounterSet, std::unordered_set &NonUniformSet); void LowerHLCreateHandle(); - // Change struct type to legacy layout for cbuf and struct buf. - void UpdateStructTypeForLegacyLayout(); + void MarkNonUniform(std::unordered_set &NonUniformSet); // Translate precise attribute into HL function call. void TranslatePreciseAttribute(); @@ -395,6 +387,17 @@ void DxilGenerationPass::LowerHLCreateHandle() { } } +void DxilGenerationPass::MarkNonUniform( + std::unordered_set &NonUniformSet) { + for (Value *V : NonUniformSet) { + for (User *U : V->users()) { + if (Instruction *I = dyn_cast(U)) { + DxilMDHelper::MarkNonUniform(I); + } + } + } +} + static Value *MergeImmResClass(Value *resClass) { if (ConstantInt *Imm = dyn_cast(resClass)) { return resClass; @@ -603,403 +606,6 @@ void DxilGenerationPass::MarkUpdateCounter( } } -void DxilGenerationPass::TranslateDxilResourceUses( - DxilResourceBase &res, std::unordered_set &UpdateCounterSet, - std::unordered_set &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(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::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(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 handleMapOnFunction; - - Value *createHandleArgs[] = {opArg, resClassArg, resIDArg, resLowerBound, - isUniformRes}; - - for (iplist::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(user)) { - if (UpdateCounterSet.count(ldInst)) { - DxilResource *resource = llvm::dyn_cast(&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(user) != nullptr, - "else AddOpcodeParamForIntrinsic in CodeGen did not patch uses " - "to only have ld/st refer to temp object"); - GEPOperator *GEP = cast(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 > Builder; - if (GetElementPtrInst *GEPInst = dyn_cast(GEP)) { - Builder = std::make_unique >(GEPInst); - } else { - Builder = std::make_unique >(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(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(*(GEPU++)); - if (UpdateCounterSet.count(ldInst)) { - DxilResource *resource = dyn_cast(&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 &UpdateCounterSet, - std::unordered_set &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 &resSet) { - unsigned startOpIdx = 0; - // Skip Cond for Select. - if (isa(Res)) - startOpIdx = 1; - else if (!isa(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(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 &handleMap, - std::unordered_set &nonUniformOps) { - unsigned numOperands = Res->getNumOperands(); - - unsigned startOpIdx = 0; - // Skip Cond for Select. - if (SelectInst *Sel = dyn_cast(Res)) - startOpIdx = 1; - - CallInst *Handle = handleMap[Res]; - - Instruction *resClass = cast( - Handle->getArgOperand(DXIL::OperandIndex::kCreateHandleResClassOpIdx)); - Instruction *resID = cast( - Handle->getArgOperand(DXIL::OperandIndex::kCreateHandleResIDOpIdx)); - Instruction *resAddr = cast( - Handle->getArgOperand(DXIL::OperandIndex::kCreateHandleResIndexOpIdx)); - - for (unsigned i = startOpIdx; i < numOperands; i++) { - if (!isa(Res->getOperand(i))) { - EmitResMappingError(Res); - continue; - } - Instruction *ResOp = cast(Res->getOperand(i)); - CallInst *HandleOp = dyn_cast(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 objPhiList; - std::unordered_set objSelectList; - std::unordered_set resSelectSet; - for (User *U : createHandle->users()) { - for (User *HandleU : U->users()) { - Instruction *I = cast(HandleU); - if (!isa(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 handleMap; - for (Instruction *Res : resSelectSet) { - unsigned numOperands = Res->getNumOperands(); - IRBuilder<> Builder(Res); - - unsigned startOpIdx = 0; - // Skip Cond for Select. - if (SelectInst *Sel = dyn_cast(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(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 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(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 &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(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(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 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(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(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(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(User)) { - if (!User->user_empty()) - I->replaceAllUsesWith(UndefValue::get(I->getType())); - - I->eraseFromParent(); - } else { - ConstantExpr *CE = cast(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); -} /////////////////////////////////////////////////////////////////////////////// diff --git a/lib/HLSL/DxilMetadataHelper.cpp b/lib/HLSL/DxilMetadataHelper.cpp index 81bddcf53..9fdf1b39b 100644 --- a/lib/HLSL/DxilMetadataHelper.cpp +++ b/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 diff --git a/lib/HLSL/DxilValidation.cpp b/lib/HLSL/DxilValidation.cpp index 8ced390e5..f417312cb 100644 --- a/lib/HLSL/DxilValidation.cpp +++ b/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) { diff --git a/lib/Transforms/Utils/Local.cpp b/lib/Transforms/Utils/Local.cpp index 50ca6234d..183f07cd8 100644 --- a/lib/Transforms/Utils/Local.cpp +++ b/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