-
Notifications
You must be signed in to change notification settings - Fork 830
Remove unused target types from !dx.targetTypes metadata
#8202
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1641,6 +1641,110 @@ INITIALIZE_PASS(DxilEmitMetadata, "hlsl-dxilemit", "HLSL DXIL Metadata Emit", | |
|
|
||
| namespace { | ||
|
|
||
| // DxilTrimTargetTypes pass makes sure the !dx.targetTypes metadata only | ||
| // contains types that are actually used by the shader. | ||
|
|
||
| class DxilTrimTargetTypes : public ModulePass { | ||
| public: | ||
| static char ID; // Pass identification, replacement for typeid | ||
| explicit DxilTrimTargetTypes() : ModulePass(ID) {} | ||
|
|
||
| StringRef getPassName() const override { | ||
| return "HLSL DXIL Trim Target Types"; | ||
| } | ||
|
|
||
| // Map of target type to its metadata node and usage flag. | ||
| using TargetTypesUsageMap = | ||
| SmallDenseMap<llvm::Type *, std::pair<MDTuple *, bool>, 16>; | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Question: do we actually need to track whether or not types are used, or should we just collect the list of types that are and replace the metadata? It seems to me that re-computing the set of used types is probably faster than looking at the existing set and determining if it is correct.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If we just collect the list of types that are used, we will need to parse the type name to reconstruct the metadata constants. I was under the impression that that's what we want to avoid. |
||
|
|
||
| void markTargetTypeAsUsed(TargetTypesUsageMap &Map, llvm::Type *Ty) { | ||
| auto It = Map.find(Ty); | ||
| assert(It != Map.end() && | ||
| "used target type is not in dx.targetTypes metadata list"); | ||
| (*It).second.second = true; | ||
| } | ||
|
|
||
| bool runOnModule(Module &M) override { | ||
| NamedMDNode *TargetTypesMDNode = | ||
| M.getNamedMetadata(DxilMDHelper::kDxilTargetTypesMDName); | ||
| if (!TargetTypesMDNode) | ||
| return false; | ||
|
|
||
| // Add all target types that from "dx.targetTypes" metadata to the map | ||
| // to track their usage. | ||
| TargetTypesUsageMap TargetTypesMap; | ||
| for (MDNode *Node : TargetTypesMDNode->operands()) { | ||
| MDTuple *TypeMD = dyn_cast<MDTuple>(Node); | ||
| if (!TypeMD || TypeMD->getNumOperands() == 0) | ||
| continue; | ||
|
|
||
| ConstantAsMetadata *ConstMD = | ||
| dyn_cast<ConstantAsMetadata>(TypeMD->getOperand(0).get()); | ||
| if (!ConstMD) | ||
| continue; | ||
|
|
||
| Constant *TypeUndefPtr = ConstMD->getValue(); | ||
| llvm::Type *Ty = TypeUndefPtr->getType(); | ||
| TargetTypesMap.try_emplace(Ty, std::make_pair(TypeMD, false)); | ||
| } | ||
|
|
||
| // Scan all LinAlgMatrix functions and check the return type and argument | ||
| // types to find all used target types. | ||
| for (const llvm::Function &F : M.functions()) { | ||
| if (!F.isDeclaration()) | ||
| continue; | ||
|
|
||
| // Currently only LinAlgMatrix ops use target types. | ||
| if (!OP::IsDxilOpLinAlgFuncName(F.getName())) | ||
| continue; | ||
|
|
||
| llvm::Type *RetTy = F.getReturnType(); | ||
| if (dxilutil::IsHLSLKnownTargetType(RetTy)) | ||
| markTargetTypeAsUsed(TargetTypesMap, RetTy); | ||
|
|
||
| for (const auto &Arg : F.args()) { | ||
| llvm::Type *Ty = Arg.getType(); | ||
| if (dxilutil::IsHLSLKnownTargetType(Ty)) | ||
| markTargetTypeAsUsed(TargetTypesMap, Ty); | ||
| } | ||
| } | ||
|
|
||
| // Remove old metadata node from the module. | ||
| TargetTypesMDNode->eraseFromParent(); | ||
|
|
||
| // Create a new one with the used target types. | ||
| NamedMDNode *NewTargetTypesMDNode = | ||
| M.getOrInsertNamedMetadata(DxilMDHelper::kDxilTargetTypesMDName); | ||
| for (auto &Entry : TargetTypesMap) { | ||
| MDTuple *Node = Entry.second.first; | ||
| bool IsUsed = Entry.second.second; | ||
| if (IsUsed) | ||
| NewTargetTypesMDNode->addOperand(Node); | ||
| } | ||
|
|
||
| // If no target type is used, remove the new metadata node from module. | ||
| if (NewTargetTypesMDNode->getNumOperands() == 0) | ||
| NewTargetTypesMDNode->eraseFromParent(); | ||
|
|
||
| return true; | ||
| } | ||
| }; | ||
|
|
||
| } // namespace | ||
|
|
||
| char DxilTrimTargetTypes::ID = 0; | ||
|
|
||
| ModulePass *llvm::createDxilTrimTargetTypesPass() { | ||
| return new DxilTrimTargetTypes(); | ||
| } | ||
|
|
||
| INITIALIZE_PASS(DxilTrimTargetTypes, "hlsl-trim-target-types", | ||
| "HLSL DXIL Trim Target Types", false, false) | ||
|
|
||
| /////////////////////////////////////////////////////////////////////////////// | ||
|
|
||
| namespace { | ||
|
|
||
| const StringRef UniNoWaveSensitiveGradientErrMsg = | ||
| "Gradient operations are not affected by wave-sensitive data or control " | ||
| "flow."; | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,40 @@ | ||
| // REQUIRES: dxil-1-10 | ||
| // RUN: %dxc -T cs_6_10 %s | FileCheck %s | ||
|
|
||
| // This test is using 2 LinAlgMatrix operations: | ||
| // - __builtin_LinAlg_FillMatrix - has the matrix as a return value | ||
| // - __builtin_LinAlg_MatrixLength - has the matrix as an argument | ||
| // This is done to verify that target types are correctly collected from both | ||
| // return values and arguments of LinAlgMatrix operations. | ||
|
|
||
| uint useMatrix1() { | ||
| // Matrix<ComponentType::I32, 4, 5, MatrixUse::A, MatrixScope::Thread> m; | ||
| __builtin_LinAlgMatrix [[__LinAlgMatrix_Attributes(4, 4, 5, 0, 0)]] mat1; | ||
| // mat1 = Matrix::Splat(5); | ||
| __builtin_LinAlg_FillMatrix(mat1, 5); | ||
|
|
||
| // Matrix<ComponentType::I32, 4, 5, MatrixUse::A, MatrixScope::Thread> m; | ||
| __builtin_LinAlgMatrix [[__LinAlgMatrix_Attributes(5, 3, 3, 0, 0)]] mat2; | ||
| // mat2 = Matrix::Splat(5); | ||
| return __builtin_LinAlg_MatrixLength(mat2); | ||
| } | ||
|
|
||
| uint useMatrix2() { | ||
| // Matrix<ComponentType::F64, 2, 2, MatrixUse::B, MatrixScope::Wave> m; | ||
| __builtin_LinAlgMatrix [[__LinAlgMatrix_Attributes(10, 2, 2, 1, 1)]] mat3; | ||
| // mat3 = Matrix::Splat(5); | ||
| __builtin_LinAlg_FillMatrix(mat3, 5); | ||
| return __builtin_LinAlg_MatrixLength(mat3); | ||
| } | ||
|
|
||
| RWBuffer<uint> Out; | ||
|
|
||
| [numthreads(4,1,1)] | ||
| void main() { | ||
| Out[0] = useMatrix1(); | ||
| } | ||
|
|
||
| // CHECK: !dx.targetTypes = !{!{{[0-9]+}}, !{{[0-9]+}}} | ||
| // CHECK: !{{[0-9]+}} = !{%dx.types.LinAlgMatrixC4M4N5U0S0 undef, i32 4, i32 4, i32 5, i32 0, i32 0} | ||
| // CHECK: !{{[0-9]+}} = !{%dx.types.LinAlgMatrixC5M3N3U0S0 undef, i32 5, i32 3, i32 3, i32 0, i32 0} | ||
| // CHECK-NOT: !{%dx.types.LinAlgMatrixC10M2N2U1S1 undef, i32 10, i32 2, i32 2, i32 1, i32 1} |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,96 @@ | ||
| // REQUIRES: dxil-1-10 | ||
| // RUN: %dxc -T lib_6_x -DLIB1 %s | FileCheck %s --check-prefix=LIB1 | ||
| // RUN: %dxc -T lib_6_x -DLIB1 -Fo %t.lib1.dxbc %s | ||
| // RUN: %dxc -T lib_6_x -DLIB2 %s | FileCheck %s --check-prefix=LIB2 | ||
| // RUN: %dxc -T lib_6_x -DLIB2 -Fo %t.lib2.dxbc %s | ||
| // RUN: %dxl -T cs_6_10 -E CSMain1 "%t.lib1.dxbc;%t.lib2.dxbc" | FileCheck %s --check-prefix=CSMAIN1 | ||
| // RUN: %dxl -T cs_6_10 -E CSMain2 "%t.lib1.dxbc;%t.lib2.dxbc" | FileCheck %s --check-prefix=CSMAIN2 | ||
| // RUN: %dxl -T cs_6_10 -E CSMain3 "%t.lib1.dxbc;%t.lib2.dxbc" | FileCheck %s --check-prefix=CSMAIN3 | ||
|
|
||
| uint useMatrix1(); | ||
| uint useMatrix2(); | ||
| void useMatrix3(); | ||
|
|
||
| // This test is using 2 LinAlgMatrix operations: | ||
| // - __builtin_LinAlg_FillMatrix - has the matrix as a return value | ||
| // - __builtin_LinAlg_MatrixLength - has the matrix as an argument | ||
| // This is done to verify that target types are correctly collected from both | ||
| // return values and arguments of LinAlgMatrix operations. | ||
|
|
||
| // ---- lib1 source code --- // | ||
| #ifdef LIB1 | ||
|
|
||
| uint useMatrix1() { | ||
| // Matrix<ComponentType::I32, 4, 5, MatrixUse::A, MatrixScope::Thread> m; | ||
| __builtin_LinAlgMatrix [[__LinAlgMatrix_Attributes(4, 4, 5, 0, 0)]] mat1; | ||
| // mat1 = Matrix::Splat(5); | ||
| __builtin_LinAlg_FillMatrix(mat1, 5); | ||
| // return mat1.Length(); | ||
| return __builtin_LinAlg_MatrixLength(mat1); | ||
| } | ||
|
|
||
| uint useMatrix2() { | ||
| // Matrix<ComponentType::F64, 2, 2, MatrixUse::B, MatrixScope::Wave> m; | ||
| __builtin_LinAlgMatrix [[__LinAlgMatrix_Attributes(10, 2, 2, 1, 1)]] mat2; | ||
| // return mat2.Length(); | ||
| return __builtin_LinAlg_MatrixLength(mat2); | ||
| } | ||
|
|
||
| #endif | ||
|
|
||
| // ---- lib2 source code --- // | ||
| #ifdef LIB2 | ||
|
|
||
| void useMatrix3() { | ||
| //Matrix<ComponentType::U32, 6, 6, MatrixUse::Accumulator, MatrixScope::ThreadGroup> m; | ||
| __builtin_LinAlgMatrix [[__LinAlgMatrix_Attributes(5, 6, 6, 2, 2)]] mat3; | ||
| // mat3 = Matrix::Splat(5); | ||
| __builtin_LinAlg_FillMatrix(mat3, 5); | ||
| } | ||
|
|
||
| RWBuffer<uint> Out; | ||
|
|
||
| [shader("compute")] | ||
| [numthreads(4,1,1)] | ||
| void CSMain1() { | ||
| // no matrix used | ||
| } | ||
|
|
||
| [shader("compute")] | ||
| [numthreads(4,1,1)] | ||
| void CSMain2() { | ||
| Out[0] = useMatrix1(); | ||
| } | ||
|
|
||
| [shader("compute")] | ||
| [numthreads(4,1,1)] | ||
| void CSMain3() { | ||
| Out[0] = useMatrix2(); | ||
| useMatrix3(); | ||
| } | ||
|
|
||
| #endif | ||
|
|
||
| // Target types in lib1 | ||
| // LIB1: !dx.targetTypes = !{![[TT1:.*]], ![[TT2:.*]]} | ||
| // LIB1: ![[TT1]] = !{%dx.types.LinAlgMatrixC4M4N5U0S0 undef, i32 4, i32 4, i32 5, i32 0, i32 0} | ||
| // LIB1: ![[TT2]] = !{%dx.types.LinAlgMatrixC10M2N2U1S1 undef, i32 10, i32 2, i32 2, i32 1, i32 1} | ||
|
|
||
| // Target types in lib2 | ||
| // LIB2: !dx.targetTypes = !{![[TT3:.*]]} | ||
| // LIB2: ![[TT3]] = !{%dx.types.LinAlgMatrixC5M6N6U2S2 undef, i32 5, i32 6, i32 6, i32 2, i32 2} | ||
|
|
||
| // Target types in final module (should be only those that are used) | ||
|
|
||
| // CSMain1 doesn't use any matrix, so the target types should be filtered out from the final module. | ||
| // CSMAIN1-NOT: !dx.targetTypes | ||
|
|
||
| // CSMain2 uses one type of matrix | ||
| // CSMAIN2: !dx.targetTypes = !{!{{[0-9]+}}} | ||
| // CSMAIN2: !{{[0-9]+}} = !{%dx.types.LinAlgMatrixC4M4N5U0S0 undef, i32 4, i32 4, i32 5, i32 0, i32 0} | ||
|
|
||
| // CSMain3 uses two types of matrices | ||
| // CSMAIN3: !dx.targetTypes = !{!{{[0-9]+}}, !{{[0-9]+}}} | ||
| // CSMAIN3-DAG: !{{[0-9]+}} = !{%dx.types.LinAlgMatrixC10M2N2U1S1 undef, i32 10, i32 2, i32 2, i32 1, i32 1} | ||
| // CSMAIN3-DAG: !{{[0-9]+}} = !{%dx.types.LinAlgMatrixC5M6N6U2S2 undef, i32 5, i32 6, i32 6, i32 2, i32 2} | ||
| // CSMAIN3-NOT: !{%dx.types.LinAlgMatrixC10M2N2U1S1 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The dx.types version of this was put into DxilUtil in this PR https://github.com/microsoft/DirectXShaderCompiler/pull/8186/changes
Might make sense to have them next to each other?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is probably fine in either place, maybe a better fit to leave it here. The reason being that all of these are called
*Prefix, they are all used in DXIL ops,m_NamePrefixis equal to"dx.op", so IMHOm_LinAlgNamePrefixwith"dx.op.linAlg"fits here quite well.