Skip to content

Commit c8b3d79

Browse files
authored
[DXIL] Remove incompatible metadata types when preparing DXIL. (#136386)
This PR introduces a Metadata Node Kind allowlist. The purpose is to prevent newer Metadata Node Kinds to be used and inserted into the outputted DXIL module. Only the metadata kinds that are accepted in the DXIL Validator are on the allowlist. The Github DXC validator doesn't support these newer Metadata Node Kinds, so we need to filter them out. We introduce this restrictive allowlist into LLVM and strip all metadata that isn't found in the list. The accompanying test would add the `llvm.loop.mustprogress` metadata node kind, but thanks to the allowlist, filters it out, and so the whitelist is proven to work. The test also has two separate metadata kinds that are on the allowlist, and remain after the DXIL Prepare pass.
1 parent cebaf0c commit c8b3d79

File tree

2 files changed

+47
-0
lines changed

2 files changed

+47
-0
lines changed

llvm/lib/Target/DirectX/DXILPrepare.cpp

+15
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,15 @@ class DXILPrepareModule : public ModulePass {
161161
Builder.getPtrTy(PtrTy->getAddressSpace())));
162162
}
163163

164+
static std::array<unsigned, 6> getCompatibleInstructionMDs(llvm::Module &M) {
165+
return {M.getMDKindID("dx.nonuniform"),
166+
M.getMDKindID("dx.controlflow.hints"),
167+
M.getMDKindID("dx.precise"),
168+
llvm::LLVMContext::MD_range,
169+
llvm::LLVMContext::MD_alias_scope,
170+
llvm::LLVMContext::MD_noalias};
171+
}
172+
164173
public:
165174
bool runOnModule(Module &M) override {
166175
PointerTypeMap PointerTypes = PointerTypeAnalysis::run(M);
@@ -176,6 +185,9 @@ class DXILPrepareModule : public ModulePass {
176185
VersionTuple ValVer = MetadataInfo.ValidatorVersion;
177186
bool SkipValidation = ValVer.getMajor() == 0 && ValVer.getMinor() == 0;
178187

188+
// construct allowlist of valid metadata node kinds
189+
std::array<unsigned, 6> DXILCompatibleMDs = getCompatibleInstructionMDs(M);
190+
179191
for (auto &F : M.functions()) {
180192
F.removeFnAttrs(AttrMask);
181193
F.removeRetAttrs(AttrMask);
@@ -189,6 +201,9 @@ class DXILPrepareModule : public ModulePass {
189201
for (auto &BB : F) {
190202
IRBuilder<> Builder(&BB);
191203
for (auto &I : make_early_inc_range(BB)) {
204+
205+
I.dropUnknownNonDebugMetadata(DXILCompatibleMDs);
206+
192207
if (I.getOpcode() == Instruction::FNeg) {
193208
Builder.SetInsertPoint(&I);
194209
Value *In = I.getOperand(0);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
; RUN: opt -S --dxil-prepare %s | FileCheck %s
2+
3+
; Test that only metadata nodes that are valid in DXIL are allowed through
4+
5+
target triple = "dxilv1.0-unknown-shadermodel6.0-compute"
6+
7+
; Function Attrs: noinline nounwind memory(readwrite, inaccessiblemem: none)
8+
define void @main(i32* %ptr) {
9+
entry:
10+
; metadata ID changes to 0 once the current !0 and !1 are removed
11+
; since they aren't in the allowlist. range needs a payload.
12+
; CHECK: %val = load i32, ptr %ptr, align 4, !range [[RANGEMD:![0-9]+]]
13+
%val = load i32, ptr %ptr, align 4, !range !2
14+
15+
%cmp.i = icmp ult i32 1, 2
16+
; Ensure that the !llvm.loop metadata node gets dropped.
17+
; CHECK: br i1 %cmp.i, label %_Z4mainDv3_j.exit, label %_Z4mainDv3_j.exit{{$}}
18+
br i1 %cmp.i, label %_Z4mainDv3_j.exit, label %_Z4mainDv3_j.exit, !llvm.loop !0
19+
20+
_Z4mainDv3_j.exit: ; preds = %for.body.i, %entry
21+
ret void
22+
}
23+
24+
; These next check lines check that only the range metadata remains
25+
; No more metadata should be necessary, the rest (the current 0 and 1)
26+
; should be removed.
27+
; CHECK-NOT: !{!"llvm.loop.mustprogress"}
28+
; CHECK: [[RANGEMD]] = !{i32 1, i32 5}
29+
; CHECK-NOT: !{!"llvm.loop.mustprogress"}
30+
!0 = distinct !{!0, !1}
31+
!1 = !{!"llvm.loop.mustprogress"}
32+
!2 = !{i32 1, i32 5}

0 commit comments

Comments
 (0)