Skip to content

Commit 727f392

Browse files
authored
[DirectX] Implement Shader Flags Analysis for ResMayNotAlias (#131070)
Fixes #112270 Completed ACs: - `-res-may-alias` clang-dxc command-line option added - It inserts and sets a module metadata flag `dx.resmayalias` to 1 - Shader flag set appropriately: - The flag IS NOT set if DXIL Version <= 1.6 OR the command-line option `-res-may-alias` is specified - Otherwise the flag IS set when: - DXIL Version > 1.7 AND function uses UAVs, OR - DXIL Version <= 1.7 AND UAVs present globally - Add tests - Tests for Shader Models 6.6, 6.7, and 6.8 corresponding to DXIL Versions 1.6, 1.7, and 1.8 - Tests (`res-may-alias-0.ll`/`res-may-alias-1.ll`) for when the module metadata flag `dx.resmayalias` is set to 0 or 1 respectively - A frontend test (`res-may-alias.hlsl`) for testing that that the command-line option `-res-may-alias` inserts `dx.resmayalias` module metadata correctly
1 parent b39ab7a commit 727f392

File tree

13 files changed

+258
-8
lines changed

13 files changed

+258
-8
lines changed

clang/include/clang/Basic/CodeGenOptions.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -476,6 +476,9 @@ CODEGENOPT(ImportCallOptimization, 1, 0)
476476
/// (BlocksRuntime) on Windows.
477477
CODEGENOPT(StaticClosure, 1, 0)
478478

479+
/// Assume that UAVs/SRVs may alias
480+
CODEGENOPT(ResMayAlias, 1, 0)
481+
479482
/// FIXME: Make DebugOptions its own top-level .def file.
480483
#include "DebugOptions.def"
481484

clang/include/clang/Driver/Options.td

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9131,6 +9131,11 @@ def dxil_validator_version : Option<["/", "-"], "validator-version", KIND_SEPARA
91319131
HelpText<"Override validator version for module. Format: <major.minor>;"
91329132
"Default: DXIL.dll version or current internal version">,
91339133
MarshallingInfoString<TargetOpts<"DxilValidatorVersion">, "\"1.8\"">;
9134+
def res_may_alias : Option<["/", "-"], "res-may-alias", KIND_FLAG>,
9135+
Group<dxc_Group>, Flags<[HelpHidden]>,
9136+
Visibility<[DXCOption, ClangOption, CC1Option]>,
9137+
HelpText<"Assume that UAVs/SRVs may alias">,
9138+
MarshallingInfoFlag<CodeGenOpts<"ResMayAlias">>;
91349139
def target_profile : DXCJoinedOrSeparate<"T">, MetaVarName<"<profile>">,
91359140
HelpText<"Set target profile">,
91369141
Values<"ps_6_0, ps_6_1, ps_6_2, ps_6_3, ps_6_4, ps_6_5, ps_6_6, ps_6_7,"

clang/lib/CodeGen/CGHLSLRuntime.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -282,11 +282,14 @@ void CGHLSLRuntime::addHLSLBufferLayoutType(const RecordType *StructType,
282282

283283
void CGHLSLRuntime::finishCodeGen() {
284284
auto &TargetOpts = CGM.getTarget().getTargetOpts();
285+
auto &CodeGenOpts = CGM.getCodeGenOpts();
285286
auto &LangOpts = CGM.getLangOpts();
286287
llvm::Module &M = CGM.getModule();
287288
Triple T(M.getTargetTriple());
288289
if (T.getArch() == Triple::ArchType::dxil)
289290
addDxilValVersion(TargetOpts.DxilValidatorVersion, M);
291+
if (CodeGenOpts.ResMayAlias)
292+
M.setModuleFlag(llvm::Module::ModFlagBehavior::Error, "dx.resmayalias", 1);
290293

291294
// NativeHalfType corresponds to the -fnative-half-type clang option which is
292295
// aliased by clang-dxc's -enable-16bit-types option. This option is used to

clang/lib/Driver/ToolChains/Clang.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3974,6 +3974,7 @@ static void RenderOpenCLOptions(const ArgList &Args, ArgStringList &CmdArgs,
39743974
static void RenderHLSLOptions(const ArgList &Args, ArgStringList &CmdArgs,
39753975
types::ID InputType) {
39763976
const unsigned ForwardedArguments[] = {options::OPT_dxil_validator_version,
3977+
options::OPT_res_may_alias,
39773978
options::OPT_D,
39783979
options::OPT_I,
39793980
options::OPT_O,
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// RUN: %clang_dxc -res-may-alias -T lib_6_3 -HV 202x -Vd -Xclang -emit-llvm %s | FileCheck %s --check-prefix=FLAG
2+
// RUN: %clang_dxc -T lib_6_3 -HV 202x -Vd -Xclang -emit-llvm %s | FileCheck %s --check-prefix=NOFLAG
3+
4+
// FLAG-DAG: ![[RMA:.*]] = !{i32 1, !"dx.resmayalias", i32 1}
5+
// FLAG-DAG: !llvm.module.flags = !{{{.*}}![[RMA]]{{.*}}}
6+
7+
// NOFLAG-NOT: dx.resmayalias

llvm/lib/Target/DirectX/DXILShaderFlags.cpp

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,8 @@ static bool checkWaveOps(Intrinsic::ID IID) {
7474
/// \param I Instruction to check.
7575
void ModuleShaderFlags::updateFunctionFlags(ComputedShaderFlags &CSF,
7676
const Instruction &I,
77-
DXILResourceTypeMap &DRTM) {
77+
DXILResourceTypeMap &DRTM,
78+
const ModuleMetadataInfo &MMDI) {
7879
if (!CSF.Doubles)
7980
CSF.Doubles = I.getType()->isDoubleTy();
8081

@@ -128,8 +129,15 @@ void ModuleShaderFlags::updateFunctionFlags(ComputedShaderFlags &CSF,
128129
switch (II->getIntrinsicID()) {
129130
default:
130131
break;
131-
case Intrinsic::dx_resource_handlefrombinding:
132-
switch (DRTM[cast<TargetExtType>(II->getType())].getResourceKind()) {
132+
case Intrinsic::dx_resource_handlefrombinding: {
133+
dxil::ResourceTypeInfo &RTI = DRTM[cast<TargetExtType>(II->getType())];
134+
135+
// Set ResMayNotAlias if DXIL version >= 1.8 and function uses UAVs
136+
if (!CSF.ResMayNotAlias && CanSetResMayNotAlias &&
137+
MMDI.DXILVersion >= VersionTuple(1, 8) && RTI.isUAV())
138+
CSF.ResMayNotAlias = true;
139+
140+
switch (RTI.getResourceKind()) {
133141
case dxil::ResourceKind::StructuredBuffer:
134142
case dxil::ResourceKind::RawBuffer:
135143
CSF.EnableRawAndStructuredBuffers = true;
@@ -138,6 +146,7 @@ void ModuleShaderFlags::updateFunctionFlags(ComputedShaderFlags &CSF,
138146
break;
139147
}
140148
break;
149+
}
141150
case Intrinsic::dx_resource_load_typedbuffer: {
142151
dxil::ResourceTypeInfo &RTI =
143152
DRTM[cast<TargetExtType>(II->getArgOperand(0)->getType())];
@@ -163,7 +172,18 @@ void ModuleShaderFlags::updateFunctionFlags(ComputedShaderFlags &CSF,
163172

164173
/// Construct ModuleShaderFlags for module Module M
165174
void ModuleShaderFlags::initialize(Module &M, DXILResourceTypeMap &DRTM,
175+
DXILResourceMap &DRM,
166176
const ModuleMetadataInfo &MMDI) {
177+
178+
CanSetResMayNotAlias = MMDI.DXILVersion >= VersionTuple(1, 7);
179+
180+
// Check if -res-may-alias was provided on the command line.
181+
// The command line option will set the dx.resmayalias module flag to 1.
182+
if (auto *RMA = mdconst::extract_or_null<ConstantInt>(
183+
M.getModuleFlag("dx.resmayalias")))
184+
if (RMA->getValue() != 0)
185+
CanSetResMayNotAlias = false;
186+
167187
CallGraph CG(M);
168188

169189
// Compute Shader Flags Mask for all functions using post-order visit of SCC
@@ -188,6 +208,11 @@ void ModuleShaderFlags::initialize(Module &M, DXILResourceTypeMap &DRTM,
188208
continue;
189209
}
190210

211+
// Set ResMayNotAlias to true if DXIL version < 1.8 and there are UAVs
212+
// present globally.
213+
if (CanSetResMayNotAlias && MMDI.DXILVersion < VersionTuple(1, 8))
214+
SCCSF.ResMayNotAlias = !DRM.uavs().empty();
215+
191216
// Set UseNativeLowPrecision using dx.nativelowprec module metadata
192217
if (auto *NativeLowPrec = mdconst::extract_or_null<ConstantInt>(
193218
M.getModuleFlag("dx.nativelowprec")))
@@ -198,7 +223,7 @@ void ModuleShaderFlags::initialize(Module &M, DXILResourceTypeMap &DRTM,
198223
ComputedShaderFlags CSF;
199224
for (const auto &BB : *F)
200225
for (const auto &I : BB)
201-
updateFunctionFlags(CSF, I, DRTM);
226+
updateFunctionFlags(CSF, I, DRTM, MMDI);
202227
// Update combined shader flags mask for all functions in this SCC
203228
SCCSF.merge(CSF);
204229

@@ -268,10 +293,11 @@ AnalysisKey ShaderFlagsAnalysis::Key;
268293
ModuleShaderFlags ShaderFlagsAnalysis::run(Module &M,
269294
ModuleAnalysisManager &AM) {
270295
DXILResourceTypeMap &DRTM = AM.getResult<DXILResourceTypeAnalysis>(M);
296+
DXILResourceMap &DRM = AM.getResult<DXILResourceAnalysis>(M);
271297
const ModuleMetadataInfo MMDI = AM.getResult<DXILMetadataAnalysis>(M);
272298

273299
ModuleShaderFlags MSFI;
274-
MSFI.initialize(M, DRTM, MMDI);
300+
MSFI.initialize(M, DRTM, DRM, MMDI);
275301

276302
return MSFI;
277303
}
@@ -301,16 +327,18 @@ PreservedAnalyses ShaderFlagsAnalysisPrinter::run(Module &M,
301327
bool ShaderFlagsAnalysisWrapper::runOnModule(Module &M) {
302328
DXILResourceTypeMap &DRTM =
303329
getAnalysis<DXILResourceTypeWrapperPass>().getResourceTypeMap();
330+
DXILResourceMap &DRM = getAnalysis<DXILResourceWrapperPass>().getBindingMap();
304331
const ModuleMetadataInfo MMDI =
305332
getAnalysis<DXILMetadataAnalysisWrapperPass>().getModuleMetadata();
306333

307-
MSFI.initialize(M, DRTM, MMDI);
334+
MSFI.initialize(M, DRTM, DRM, MMDI);
308335
return false;
309336
}
310337

311338
void ShaderFlagsAnalysisWrapper::getAnalysisUsage(AnalysisUsage &AU) const {
312339
AU.setPreservesAll();
313340
AU.addRequiredTransitive<DXILResourceTypeWrapperPass>();
341+
AU.addRequiredTransitive<DXILResourceWrapperPass>();
314342
AU.addRequired<DXILMetadataAnalysisWrapperPass>();
315343
}
316344

llvm/lib/Target/DirectX/DXILShaderFlags.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ namespace llvm {
2828
class Module;
2929
class GlobalVariable;
3030
class DXILResourceTypeMap;
31+
class DXILResourceMap;
3132

3233
namespace dxil {
3334

@@ -84,20 +85,21 @@ struct ComputedShaderFlags {
8485
};
8586

8687
struct ModuleShaderFlags {
87-
void initialize(Module &, DXILResourceTypeMap &DRTM,
88+
void initialize(Module &, DXILResourceTypeMap &DRTM, DXILResourceMap &DRM,
8889
const ModuleMetadataInfo &MMDI);
8990
const ComputedShaderFlags &getFunctionFlags(const Function *) const;
9091
const ComputedShaderFlags &getCombinedFlags() const { return CombinedSFMask; }
9192

9293
private:
94+
bool CanSetResMayNotAlias;
9395
/// Map of Function-Shader Flag Mask pairs representing properties of each of
9496
/// the functions in the module. Shader Flags of each function represent both
9597
/// module-level and function-level flags
9698
DenseMap<const Function *, ComputedShaderFlags> FunctionFlags;
9799
/// Combined Shader Flag Mask of all functions of the module
98100
ComputedShaderFlags CombinedSFMask{};
99101
void updateFunctionFlags(ComputedShaderFlags &, const Instruction &,
100-
DXILResourceTypeMap &);
102+
DXILResourceTypeMap &, const ModuleMetadataInfo &);
101103
};
102104

103105
class ShaderFlagsAnalysis : public AnalysisInfoMixin<ShaderFlagsAnalysis> {
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
; RUN: opt -S --passes="print-dx-shader-flags" 2>&1 %s | FileCheck %s
2+
3+
; This test checks to ensure that setting the LLVM module flag "dx.resmayalias"
4+
; to 0 has no effect on the DXIL shader flag analysis for the flag
5+
; ResMayNotAlias.
6+
7+
target triple = "dxil-pc-shadermodel6.8-library"
8+
9+
; CHECK: Combined Shader Flags for Module
10+
; CHECK-NEXT: Shader Flags Value: 0x200000010
11+
12+
; CHECK: Note: extra DXIL module flags:
13+
; CHECK: Raw and Structured buffers
14+
; CHECK: Any UAV may not alias any other UAV
15+
;
16+
17+
; CHECK: Function loadUAV : 0x20000000
18+
define float @loadUAV() #0 {
19+
%res = call target("dx.TypedBuffer", float, 1, 0, 0)
20+
@llvm.dx.resource.handlefrombinding(i32 0, i32 0, i32 1, i32 0, i1 false)
21+
%load = call {float, i1} @llvm.dx.resource.load.typedbuffer(
22+
target("dx.TypedBuffer", float, 1, 0, 0) %res, i32 0)
23+
%val = extractvalue {float, i1} %load, 0
24+
ret float %val
25+
}
26+
27+
; CHECK: Function loadSRV : 0x00000010
28+
define float @loadSRV() #0 {
29+
%res = tail call target("dx.RawBuffer", float, 0, 0)
30+
@llvm.dx.resource.handlefrombinding(i32 0, i32 0, i32 1, i32 0, i1 false)
31+
%load = call {float, i1} @llvm.dx.resource.load.rawbuffer(
32+
target("dx.RawBuffer", float, 0, 0) %res, i32 0, i32 0)
33+
%val = extractvalue { float, i1 } %load, 0
34+
ret float %val
35+
}
36+
37+
!llvm.module.flags = !{!0}
38+
39+
; dx.resmayalias should never appear with a value of 0.
40+
; But if it does, ensure that it has no effect.
41+
!0 = !{i32 1, !"dx.resmayalias", i32 0}
42+
43+
attributes #0 = { convergent norecurse nounwind "hlsl.export"}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
; RUN: opt -S --passes="print-dx-shader-flags" 2>&1 %s | FileCheck %s
2+
3+
; This test checks to ensure that setting the LLVM module flag "dx.resmayalias"
4+
; to 1 prevents the DXIL shader flag analysis from setting the flag
5+
; ResMayNotAlias.
6+
7+
target triple = "dxil-pc-shadermodel6.8-library"
8+
9+
; CHECK: Combined Shader Flags for Module
10+
; CHECK-NEXT: Shader Flags Value: 0x00000010
11+
12+
; CHECK: Note: extra DXIL module flags:
13+
; CHECK: Raw and Structured buffers
14+
; CHECK-NOT: Any UAV may not alias any other UAV
15+
;
16+
17+
; CHECK: Function loadUAV : 0x00000000
18+
define float @loadUAV() #0 {
19+
%res = call target("dx.TypedBuffer", float, 1, 0, 0)
20+
@llvm.dx.resource.handlefrombinding(i32 0, i32 0, i32 1, i32 0, i1 false)
21+
%load = call {float, i1} @llvm.dx.resource.load.typedbuffer(
22+
target("dx.TypedBuffer", float, 1, 0, 0) %res, i32 0)
23+
%val = extractvalue {float, i1} %load, 0
24+
ret float %val
25+
}
26+
27+
; CHECK: Function loadSRV : 0x00000010
28+
define float @loadSRV() #0 {
29+
%res = tail call target("dx.RawBuffer", float, 0, 0)
30+
@llvm.dx.resource.handlefrombinding(i32 0, i32 0, i32 1, i32 0, i1 false)
31+
%load = call {float, i1} @llvm.dx.resource.load.rawbuffer(
32+
target("dx.RawBuffer", float, 0, 0) %res, i32 0, i32 0)
33+
%val = extractvalue { float, i1 } %load, 0
34+
ret float %val
35+
}
36+
37+
!llvm.module.flags = !{!0}
38+
39+
!0 = !{i32 1, !"dx.resmayalias", i32 1}
40+
41+
attributes #0 = { convergent norecurse nounwind "hlsl.export"}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
; RUN: opt -S --passes="print-dx-shader-flags" 2>&1 %s | FileCheck %s
2+
3+
; This test checks to ensure the behavior of the DXIL shader flag analysis
4+
; for the flag ResMayNotAlias is correct when the DXIL Version is 1.6. The
5+
; ResMayNotAlias flag (0x20000000) should not be set at all.
6+
7+
target triple = "dxil-pc-shadermodel6.6-library"
8+
9+
; CHECK: Combined Shader Flags for Module
10+
; CHECK-NEXT: Shader Flags Value: 0x00000010
11+
12+
; CHECK: Note: extra DXIL module flags:
13+
; CHECK: Raw and Structured buffers
14+
; CHECK-NOT: Any UAV may not alias any other UAV
15+
;
16+
17+
; CHECK: Function loadUAV : 0x00000000
18+
define float @loadUAV() #0 {
19+
%res = call target("dx.TypedBuffer", float, 1, 0, 0)
20+
@llvm.dx.resource.handlefrombinding(i32 0, i32 0, i32 1, i32 0, i1 false)
21+
%load = call {float, i1} @llvm.dx.resource.load.typedbuffer(
22+
target("dx.TypedBuffer", float, 1, 0, 0) %res, i32 0)
23+
%val = extractvalue {float, i1} %load, 0
24+
ret float %val
25+
}
26+
27+
; CHECK: Function loadSRV : 0x00000010
28+
define float @loadSRV() #0 {
29+
%res = tail call target("dx.RawBuffer", float, 0, 0)
30+
@llvm.dx.resource.handlefrombinding(i32 0, i32 0, i32 1, i32 0, i1 false)
31+
%load = call {float, i1} @llvm.dx.resource.load.rawbuffer(
32+
target("dx.RawBuffer", float, 0, 0) %res, i32 0, i32 0)
33+
%val = extractvalue { float, i1 } %load, 0
34+
ret float %val
35+
}
36+
37+
attributes #0 = { convergent norecurse nounwind "hlsl.export"}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
; RUN: opt -S --passes="print-dx-shader-flags" 2>&1 %s | FileCheck %s
2+
3+
; This test checks to ensure the behavior of the DXIL shader flag analysis
4+
; for the flag ResMayNotAlias is correct when the DXIL Version is 1.7. The
5+
; ResMayNotAlias flag (0x20000000) should be set on all functions if there are
6+
; one or more UAVs present globally in the module.
7+
8+
target triple = "dxil-pc-shadermodel6.7-library"
9+
10+
; CHECK: Combined Shader Flags for Module
11+
; CHECK-NEXT: Shader Flags Value: 0x200000010
12+
13+
; CHECK: Note: extra DXIL module flags:
14+
; CHECK: Raw and Structured buffers
15+
; CHECK: Any UAV may not alias any other UAV
16+
;
17+
18+
; CHECK: Function loadUAV : 0x200000000
19+
define float @loadUAV() #0 {
20+
%res = call target("dx.TypedBuffer", float, 1, 0, 0)
21+
@llvm.dx.resource.handlefrombinding(i32 0, i32 0, i32 1, i32 0, i1 false)
22+
%load = call {float, i1} @llvm.dx.resource.load.typedbuffer(
23+
target("dx.TypedBuffer", float, 1, 0, 0) %res, i32 0)
24+
%val = extractvalue {float, i1} %load, 0
25+
ret float %val
26+
}
27+
28+
; CHECK: Function loadSRV : 0x200000010
29+
define float @loadSRV() #0 {
30+
%res = tail call target("dx.RawBuffer", float, 0, 0)
31+
@llvm.dx.resource.handlefrombinding(i32 0, i32 0, i32 1, i32 0, i1 false)
32+
%load = call {float, i1} @llvm.dx.resource.load.rawbuffer(
33+
target("dx.RawBuffer", float, 0, 0) %res, i32 0, i32 0)
34+
%val = extractvalue { float, i1 } %load, 0
35+
ret float %val
36+
}
37+
38+
attributes #0 = { convergent norecurse nounwind "hlsl.export"}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
; RUN: opt -S --passes="print-dx-shader-flags" 2>&1 %s | FileCheck %s
2+
3+
; This test checks to ensure the behavior of the DXIL shader flag analysis
4+
; for the flag ResMayNotAlias is correct when the DXIL Version is 1.8. The
5+
; ResMayNotAlias flag (0x20000000) should only be set when a function uses a
6+
; UAV.
7+
8+
target triple = "dxil-pc-shadermodel6.8-library"
9+
10+
; CHECK: Combined Shader Flags for Module
11+
; CHECK-NEXT: Shader Flags Value: 0x200000010
12+
13+
; CHECK: Note: extra DXIL module flags:
14+
; CHECK: Raw and Structured buffers
15+
; CHECK: Any UAV may not alias any other UAV
16+
;
17+
18+
; CHECK: Function loadUAV : 0x20000000
19+
define float @loadUAV() #0 {
20+
%res = call target("dx.TypedBuffer", float, 1, 0, 0)
21+
@llvm.dx.resource.handlefrombinding(i32 0, i32 0, i32 1, i32 0, i1 false)
22+
%load = call {float, i1} @llvm.dx.resource.load.typedbuffer(
23+
target("dx.TypedBuffer", float, 1, 0, 0) %res, i32 0)
24+
%val = extractvalue {float, i1} %load, 0
25+
ret float %val
26+
}
27+
28+
; CHECK: Function loadSRV : 0x00000010
29+
define float @loadSRV() #0 {
30+
%res = tail call target("dx.RawBuffer", float, 0, 0)
31+
@llvm.dx.resource.handlefrombinding(i32 0, i32 0, i32 1, i32 0, i1 false)
32+
%load = call {float, i1} @llvm.dx.resource.load.rawbuffer(
33+
target("dx.RawBuffer", float, 0, 0) %res, i32 0, i32 0)
34+
%val = extractvalue { float, i1 } %load, 0
35+
ret float %val
36+
}
37+
38+
attributes #0 = { convergent norecurse nounwind "hlsl.export"}

0 commit comments

Comments
 (0)