Skip to content

[DirectX] Implement Shader Flags Analysis for ResMayNotAlias #131070

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

Merged
merged 12 commits into from
Apr 10, 2025

Conversation

Icohedron
Copy link
Contributor

@Icohedron Icohedron commented Mar 13, 2025

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

@Icohedron Icohedron force-pushed the shader-flag-resmaynotalias branch from ad5fbee to 81196e0 Compare March 14, 2025 00:30
Copy link

github-actions bot commented Mar 14, 2025

✅ With the latest revision this PR passed the C/C++ code formatter.

def res_may_alias : Option<["/", "-"], "res-may-alias", KIND_FLAG>,
Group<dxc_Group>, Flags<[HelpHidden]>,
Visibility<[DXCOption, ClangOption, CC1Option]>,
HelpText<"Assume that UAVs/SRVs may alias">,
Copy link
Contributor Author

@Icohedron Icohedron Mar 14, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This HelpText matches that found in DXC.
Doesn't the flag only affect whether or not the ResMayNotAlias flag can be set? The logic for setting the RestMayNotAlias flag only takes UAVs into consideration.
Perhaps the mention of SRVs should be removed?


; dx.resmayalias should never appear with a value of 0.
; But if it does, ensure that it has no effect.
!0 = !{i32 1, !"dx.resmayalias", i32 0}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure if this test is necessary since the -res-may-alias clang-dxc flag will set this to 1. If the clang-dxc flag is not present, then this metadata would not appear at all. Let me know if I should delete this test.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the moment we define some metadata we should expect that some user may set the field manually, so having tests for this should definitely be included

@Icohedron Icohedron marked this pull request as ready for review March 14, 2025 00:45
@llvmbot llvmbot added clang Clang issues not falling into any other category clang:driver 'clang' and 'clang++' user-facing binaries. Not 'clang-cl' clang:frontend Language frontend issues, e.g. anything involving "Sema" clang:codegen IR generation bugs: mangling, exceptions, etc. backend:DirectX HLSL HLSL Language Support labels Mar 14, 2025
@llvmbot
Copy link
Member

llvmbot commented Mar 14, 2025

@llvm/pr-subscribers-hlsl
@llvm/pr-subscribers-clang

@llvm/pr-subscribers-clang-driver

Author: Deric C. (Icohedron)

Changes

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:
    • CASE 1: command-line option -res-may-alias is NOT specified AND DXIL Version > 1.7 AND function uses UAVs
    • CASE 2: command-line option -res-may-alias is NOT specified AND DXIL Version <= 1.7 AND UAVs present globally
  • Add tests
    • A test (res-may-not-alias-shadermodel6.8.ll) for CASE 1
    • A test (res-may-not-alias-shadermodel6.7.ll) for CASE 2
    • A frontend test (res-may-alias.hlsl) for testing that the command-line option -res-may-alias sets the module metadata flag dx.resmayalias to 1, and does not set the module metadata flag dx.resmayalias if -res-may-alias is not given
    • 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

Full diff: https://github.com/llvm/llvm-project/pull/131070.diff

12 Files Affected:

  • (modified) clang/include/clang/Basic/CodeGenOptions.def (+3)
  • (modified) clang/include/clang/Driver/Options.td (+5)
  • (modified) clang/lib/CodeGen/CGHLSLRuntime.cpp (+3)
  • (modified) clang/lib/Driver/ToolChains/Clang.cpp (+1)
  • (added) clang/test/CodeGenHLSL/res-may-alias.hlsl (+7)
  • (modified) llvm/lib/Target/DirectX/DXILShaderFlags.cpp (+37-6)
  • (modified) llvm/lib/Target/DirectX/DXILShaderFlags.h (+7-2)
  • (added) llvm/test/CodeGen/DirectX/ShaderFlags/res-may-alias-0.ll (+39)
  • (added) llvm/test/CodeGen/DirectX/ShaderFlags/res-may-alias-1.ll (+37)
  • (added) llvm/test/CodeGen/DirectX/ShaderFlags/res-may-not-alias-shadermodel6.7.ll (+33)
  • (added) llvm/test/CodeGen/DirectX/ShaderFlags/res-may-not-alias-shadermodel6.8.ll (+33)
  • (modified) llvm/test/CodeGen/DirectX/ShaderFlags/typed-uav-load-additional-formats.ll (+5-4)
diff --git a/clang/include/clang/Basic/CodeGenOptions.def b/clang/include/clang/Basic/CodeGenOptions.def
index a7f5f1abbb825..a436c0ec98d5b 100644
--- a/clang/include/clang/Basic/CodeGenOptions.def
+++ b/clang/include/clang/Basic/CodeGenOptions.def
@@ -476,6 +476,9 @@ CODEGENOPT(ImportCallOptimization, 1, 0)
 /// (BlocksRuntime) on Windows.
 CODEGENOPT(StaticClosure, 1, 0)
 
+/// Assume that UAVs/SRVs may alias
+CODEGENOPT(ResMayAlias, 1, 0)
+
 /// FIXME: Make DebugOptions its own top-level .def file.
 #include "DebugOptions.def"
 
diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index 66ae8f1c7f064..9c5fd2354f95e 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -9043,6 +9043,11 @@ def dxil_validator_version : Option<["/", "-"], "validator-version", KIND_SEPARA
   HelpText<"Override validator version for module. Format: <major.minor>;"
            "Default: DXIL.dll version or current internal version">,
   MarshallingInfoString<TargetOpts<"DxilValidatorVersion">, "\"1.8\"">;
+def res_may_alias : Option<["/", "-"], "res-may-alias", KIND_FLAG>,
+  Group<dxc_Group>, Flags<[HelpHidden]>,
+  Visibility<[DXCOption, ClangOption, CC1Option]>,
+  HelpText<"Assume that UAVs/SRVs may alias">,
+  MarshallingInfoFlag<CodeGenOpts<"ResMayAlias">>;
 def target_profile : DXCJoinedOrSeparate<"T">, MetaVarName<"<profile>">,
   HelpText<"Set target profile">,
   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,"
diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp b/clang/lib/CodeGen/CGHLSLRuntime.cpp
index 5916fa6183a27..6fd8bc295e8ca 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.cpp
+++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp
@@ -283,10 +283,13 @@ void CGHLSLRuntime::addHLSLBufferLayoutType(const RecordType *StructType,
 
 void CGHLSLRuntime::finishCodeGen() {
   auto &TargetOpts = CGM.getTarget().getTargetOpts();
+  auto &CodeGenOpts = CGM.getCodeGenOpts();
   llvm::Module &M = CGM.getModule();
   Triple T(M.getTargetTriple());
   if (T.getArch() == Triple::ArchType::dxil)
     addDxilValVersion(TargetOpts.DxilValidatorVersion, M);
+  if (CodeGenOpts.ResMayAlias)
+    M.setModuleFlag(llvm::Module::ModFlagBehavior::Error, "dx.resmayalias", 1);
 
   generateGlobalCtorDtorCalls();
 }
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index fe172d923ac07..9be3939641cfc 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -3959,6 +3959,7 @@ static void RenderOpenCLOptions(const ArgList &Args, ArgStringList &CmdArgs,
 static void RenderHLSLOptions(const ArgList &Args, ArgStringList &CmdArgs,
                               types::ID InputType) {
   const unsigned ForwardedArguments[] = {options::OPT_dxil_validator_version,
+                                         options::OPT_res_may_alias,
                                          options::OPT_D,
                                          options::OPT_I,
                                          options::OPT_O,
diff --git a/clang/test/CodeGenHLSL/res-may-alias.hlsl b/clang/test/CodeGenHLSL/res-may-alias.hlsl
new file mode 100644
index 0000000000000..53ee8ee4935d8
--- /dev/null
+++ b/clang/test/CodeGenHLSL/res-may-alias.hlsl
@@ -0,0 +1,7 @@
+// RUN: %clang_cc1 -res-may-alias -finclude-default-header -triple dxil-pc-shadermodel6.3-library -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s --check-prefix=FLAG
+// RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.3-library -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s --check-prefix=NOFLAG
+
+// FLAG-DAG: ![[RMA:.*]] = !{i32 1, !"dx.resmayalias", i32 1}
+// FLAG-DAG: !llvm.module.flags = !{{{.*}}![[RMA]]{{.*}}}
+
+// NOFLAG-NOT: dx.resmayalias
diff --git a/llvm/lib/Target/DirectX/DXILShaderFlags.cpp b/llvm/lib/Target/DirectX/DXILShaderFlags.cpp
index 31fbd66dfaa2d..b05ee53798524 100644
--- a/llvm/lib/Target/DirectX/DXILShaderFlags.cpp
+++ b/llvm/lib/Target/DirectX/DXILShaderFlags.cpp
@@ -74,7 +74,8 @@ static bool checkWaveOps(Intrinsic::ID IID) {
 /// \param I Instruction to check.
 void ModuleShaderFlags::updateFunctionFlags(ComputedShaderFlags &CSF,
                                             const Instruction &I,
-                                            DXILResourceTypeMap &DRTM) {
+                                            DXILResourceTypeMap &DRTM,
+                                            const ModuleMetadataInfo &MMDI) {
   if (!CSF.Doubles)
     CSF.Doubles = I.getType()->isDoubleTy();
 
@@ -116,8 +117,17 @@ void ModuleShaderFlags::updateFunctionFlags(ComputedShaderFlags &CSF,
     switch (II->getIntrinsicID()) {
     default:
       break;
-    case Intrinsic::dx_resource_handlefrombinding:
-      switch (DRTM[cast<TargetExtType>(II->getType())].getResourceKind()) {
+    case Intrinsic::dx_resource_handlefrombinding: {
+      dxil::ResourceTypeInfo &RTI = DRTM[cast<TargetExtType>(II->getType())];
+
+      // If -res-may-alias is NOT specified, and DXIL Ver > 1.7.
+      // Then set ResMayNotAlias if function uses UAVs.
+      if (!CSF.ResMayNotAlias && !ResMayAlias &&
+          MMDI.DXILVersion > VersionTuple(1, 7) && RTI.isUAV()) {
+        CSF.ResMayNotAlias = true;
+      }
+
+      switch (RTI.getResourceKind()) {
       case dxil::ResourceKind::StructuredBuffer:
       case dxil::ResourceKind::RawBuffer:
         CSF.EnableRawAndStructuredBuffers = true;
@@ -126,6 +136,7 @@ void ModuleShaderFlags::updateFunctionFlags(ComputedShaderFlags &CSF,
         break;
       }
       break;
+    }
     case Intrinsic::dx_resource_load_typedbuffer: {
       dxil::ResourceTypeInfo &RTI =
           DRTM[cast<TargetExtType>(II->getArgOperand(0)->getType())];
@@ -151,7 +162,17 @@ void ModuleShaderFlags::updateFunctionFlags(ComputedShaderFlags &CSF,
 
 /// Construct ModuleShaderFlags for module Module M
 void ModuleShaderFlags::initialize(Module &M, DXILResourceTypeMap &DRTM,
+                                   DXILBindingMap &DBM,
                                    const ModuleMetadataInfo &MMDI) {
+
+  // Check if -res-may-alias was provided on the command line.
+  // The command line option will set the dx.resmayalias module flag to 1.
+  if (auto *RMA = mdconst::extract_or_null<ConstantInt>(
+          M.getModuleFlag("dx.resmayalias"))) {
+    if (RMA->getValue() != 0)
+      ResMayAlias = true;
+  }
+
   CallGraph CG(M);
 
   // Compute Shader Flags Mask for all functions using post-order visit of SCC
@@ -176,10 +197,16 @@ void ModuleShaderFlags::initialize(Module &M, DXILResourceTypeMap &DRTM,
         continue;
       }
 
+      // If -res-may-alias is NOT specified, and DXIL Ver <= 1.7.
+      // Then set ResMayNotAlias to true if there are UAVs present globally.
+      if (!ResMayAlias && MMDI.DXILVersion <= VersionTuple(1, 7)) {
+        SCCSF.ResMayNotAlias = !DBM.uavs().empty();
+      }
+
       ComputedShaderFlags CSF;
       for (const auto &BB : *F)
         for (const auto &I : BB)
-          updateFunctionFlags(CSF, I, DRTM);
+          updateFunctionFlags(CSF, I, DRTM, MMDI);
       // Update combined shader flags mask for all functions in this SCC
       SCCSF.merge(CSF);
 
@@ -249,10 +276,11 @@ AnalysisKey ShaderFlagsAnalysis::Key;
 ModuleShaderFlags ShaderFlagsAnalysis::run(Module &M,
                                            ModuleAnalysisManager &AM) {
   DXILResourceTypeMap &DRTM = AM.getResult<DXILResourceTypeAnalysis>(M);
+  DXILBindingMap &DBM = AM.getResult<DXILResourceBindingAnalysis>(M);
   const ModuleMetadataInfo MMDI = AM.getResult<DXILMetadataAnalysis>(M);
 
   ModuleShaderFlags MSFI;
-  MSFI.initialize(M, DRTM, MMDI);
+  MSFI.initialize(M, DRTM, DBM, MMDI);
 
   return MSFI;
 }
@@ -282,16 +310,19 @@ PreservedAnalyses ShaderFlagsAnalysisPrinter::run(Module &M,
 bool ShaderFlagsAnalysisWrapper::runOnModule(Module &M) {
   DXILResourceTypeMap &DRTM =
       getAnalysis<DXILResourceTypeWrapperPass>().getResourceTypeMap();
+  DXILBindingMap &DBM =
+      getAnalysis<DXILResourceBindingWrapperPass>().getBindingMap();
   const ModuleMetadataInfo MMDI =
       getAnalysis<DXILMetadataAnalysisWrapperPass>().getModuleMetadata();
 
-  MSFI.initialize(M, DRTM, MMDI);
+  MSFI.initialize(M, DRTM, DBM, MMDI);
   return false;
 }
 
 void ShaderFlagsAnalysisWrapper::getAnalysisUsage(AnalysisUsage &AU) const {
   AU.setPreservesAll();
   AU.addRequiredTransitive<DXILResourceTypeWrapperPass>();
+  AU.addRequiredTransitive<DXILResourceBindingWrapperPass>();
   AU.addRequired<DXILMetadataAnalysisWrapperPass>();
 }
 
diff --git a/llvm/lib/Target/DirectX/DXILShaderFlags.h b/llvm/lib/Target/DirectX/DXILShaderFlags.h
index abf7cc86259ed..b47c79cb293a5 100644
--- a/llvm/lib/Target/DirectX/DXILShaderFlags.h
+++ b/llvm/lib/Target/DirectX/DXILShaderFlags.h
@@ -28,6 +28,7 @@ namespace llvm {
 class Module;
 class GlobalVariable;
 class DXILResourceTypeMap;
+class DXILBindingMap;
 
 namespace dxil {
 
@@ -84,12 +85,16 @@ struct ComputedShaderFlags {
 };
 
 struct ModuleShaderFlags {
-  void initialize(Module &, DXILResourceTypeMap &DRTM,
+  void initialize(Module &, DXILResourceTypeMap &DRTM, DXILBindingMap &DBM,
                   const ModuleMetadataInfo &MMDI);
   const ComputedShaderFlags &getFunctionFlags(const Function *) const;
   const ComputedShaderFlags &getCombinedFlags() const { return CombinedSFMask; }
 
 private:
+  // A bool to indicate if the -res-may-alias flag was passed to clang-dxc.
+  // A module flag "dx.resmayalias" is set to 1 if true.
+  // This bool is used in the logic for setting the flag ResMayNotAlias.
+  bool ResMayAlias = false;
   /// Map of Function-Shader Flag Mask pairs representing properties of each of
   /// the functions in the module. Shader Flags of each function represent both
   /// module-level and function-level flags
@@ -97,7 +102,7 @@ struct ModuleShaderFlags {
   /// Combined Shader Flag Mask of all functions of the module
   ComputedShaderFlags CombinedSFMask{};
   void updateFunctionFlags(ComputedShaderFlags &, const Instruction &,
-                           DXILResourceTypeMap &);
+                           DXILResourceTypeMap &, const ModuleMetadataInfo &);
 };
 
 class ShaderFlagsAnalysis : public AnalysisInfoMixin<ShaderFlagsAnalysis> {
diff --git a/llvm/test/CodeGen/DirectX/ShaderFlags/res-may-alias-0.ll b/llvm/test/CodeGen/DirectX/ShaderFlags/res-may-alias-0.ll
new file mode 100644
index 0000000000000..29901de7f8e37
--- /dev/null
+++ b/llvm/test/CodeGen/DirectX/ShaderFlags/res-may-alias-0.ll
@@ -0,0 +1,39 @@
+; RUN: opt -S --passes="print-dx-shader-flags" 2>&1 %s | FileCheck %s
+
+target triple = "dxil-pc-shadermodel6.8-library"
+
+; CHECK:      Combined Shader Flags for Module
+; CHECK-NEXT: Shader Flags Value: 0x200000010
+
+; CHECK: Note: extra DXIL module flags:
+; CHECK:       Raw and Structured buffers
+; CHECK:       Any UAV may not alias any other UAV
+;
+
+; CHECK: Function loadUAV : 0x20000000
+define float @loadUAV() #0 {
+  %res = call target("dx.TypedBuffer", float, 1, 0, 0)
+      @llvm.dx.resource.handlefrombinding(i32 0, i32 0, i32 1, i32 0, i1 false)
+  %load = call {float, i1} @llvm.dx.resource.load.typedbuffer(
+      target("dx.TypedBuffer", float, 1, 0, 0) %res, i32 0)
+  %val = extractvalue {float, i1} %load, 0
+  ret float %val
+}
+
+; CHECK: Function loadSRV : 0x00000010
+define float @loadSRV() #0 {
+  %res = tail call target("dx.RawBuffer", float, 0, 0)
+      @llvm.dx.resource.handlefrombinding(i32 0, i32 0, i32 1, i32 0, i1 false)
+  %load = call {float, i1} @llvm.dx.resource.load.rawbuffer(
+      target("dx.RawBuffer", float, 0, 0) %res, i32 0, i32 0)
+  %val = extractvalue { float, i1 } %load, 0
+  ret float %val
+}
+
+!llvm.module.flags = !{!0}
+
+; dx.resmayalias should never appear with a value of 0.
+; But if it does, ensure that it has no effect.
+!0 = !{i32 1, !"dx.resmayalias", i32 0}
+
+attributes #0 = { convergent norecurse nounwind "hlsl.export"}
diff --git a/llvm/test/CodeGen/DirectX/ShaderFlags/res-may-alias-1.ll b/llvm/test/CodeGen/DirectX/ShaderFlags/res-may-alias-1.ll
new file mode 100644
index 0000000000000..98a8dd06f6020
--- /dev/null
+++ b/llvm/test/CodeGen/DirectX/ShaderFlags/res-may-alias-1.ll
@@ -0,0 +1,37 @@
+; RUN: opt -S --passes="print-dx-shader-flags" 2>&1 %s | FileCheck %s
+
+target triple = "dxil-pc-shadermodel6.8-library"
+
+; CHECK:      Combined Shader Flags for Module
+; CHECK-NEXT: Shader Flags Value: 0x00000010
+
+; CHECK: Note: extra DXIL module flags:
+; CHECK:       Raw and Structured buffers
+; CHECK-NOT:   Any UAV may not alias any other UAV
+;
+
+; CHECK: Function loadUAV : 0x00000000
+define float @loadUAV() #0 {
+  %res = call target("dx.TypedBuffer", float, 1, 0, 0)
+      @llvm.dx.resource.handlefrombinding(i32 0, i32 0, i32 1, i32 0, i1 false)
+  %load = call {float, i1} @llvm.dx.resource.load.typedbuffer(
+      target("dx.TypedBuffer", float, 1, 0, 0) %res, i32 0)
+  %val = extractvalue {float, i1} %load, 0
+  ret float %val
+}
+
+; CHECK: Function loadSRV : 0x00000010
+define float @loadSRV() #0 {
+  %res = tail call target("dx.RawBuffer", float, 0, 0)
+      @llvm.dx.resource.handlefrombinding(i32 0, i32 0, i32 1, i32 0, i1 false)
+  %load = call {float, i1} @llvm.dx.resource.load.rawbuffer(
+      target("dx.RawBuffer", float, 0, 0) %res, i32 0, i32 0)
+  %val = extractvalue { float, i1 } %load, 0
+  ret float %val
+}
+
+!llvm.module.flags = !{!0}
+
+!0 = !{i32 1, !"dx.resmayalias", i32 1}
+
+attributes #0 = { convergent norecurse nounwind "hlsl.export"}
diff --git a/llvm/test/CodeGen/DirectX/ShaderFlags/res-may-not-alias-shadermodel6.7.ll b/llvm/test/CodeGen/DirectX/ShaderFlags/res-may-not-alias-shadermodel6.7.ll
new file mode 100644
index 0000000000000..ab3eea71bf8f0
--- /dev/null
+++ b/llvm/test/CodeGen/DirectX/ShaderFlags/res-may-not-alias-shadermodel6.7.ll
@@ -0,0 +1,33 @@
+; RUN: opt -S --passes="print-dx-shader-flags" 2>&1 %s | FileCheck %s
+
+target triple = "dxil-pc-shadermodel6.7-library"
+
+; CHECK:      Combined Shader Flags for Module
+; CHECK-NEXT: Shader Flags Value: 0x200000010
+
+; CHECK: Note: extra DXIL module flags:
+; CHECK:       Raw and Structured buffers
+; CHECK:       Any UAV may not alias any other UAV
+;
+
+; CHECK: Function loadUAV : 0x200000000
+define float @loadUAV() #0 {
+  %res = call target("dx.TypedBuffer", float, 1, 0, 0)
+      @llvm.dx.resource.handlefrombinding(i32 0, i32 0, i32 1, i32 0, i1 false)
+  %load = call {float, i1} @llvm.dx.resource.load.typedbuffer(
+      target("dx.TypedBuffer", float, 1, 0, 0) %res, i32 0)
+  %val = extractvalue {float, i1} %load, 0
+  ret float %val
+}
+
+; CHECK: Function loadSRV : 0x200000010
+define float @loadSRV() #0 {
+  %res = tail call target("dx.RawBuffer", float, 0, 0)
+      @llvm.dx.resource.handlefrombinding(i32 0, i32 0, i32 1, i32 0, i1 false)
+  %load = call {float, i1} @llvm.dx.resource.load.rawbuffer(
+      target("dx.RawBuffer", float, 0, 0) %res, i32 0, i32 0)
+  %val = extractvalue { float, i1 } %load, 0
+  ret float %val
+}
+
+attributes #0 = { convergent norecurse nounwind "hlsl.export"}
diff --git a/llvm/test/CodeGen/DirectX/ShaderFlags/res-may-not-alias-shadermodel6.8.ll b/llvm/test/CodeGen/DirectX/ShaderFlags/res-may-not-alias-shadermodel6.8.ll
new file mode 100644
index 0000000000000..fb5e234f0bd93
--- /dev/null
+++ b/llvm/test/CodeGen/DirectX/ShaderFlags/res-may-not-alias-shadermodel6.8.ll
@@ -0,0 +1,33 @@
+; RUN: opt -S --passes="print-dx-shader-flags" 2>&1 %s | FileCheck %s
+
+target triple = "dxil-pc-shadermodel6.8-library"
+
+; CHECK:      Combined Shader Flags for Module
+; CHECK-NEXT: Shader Flags Value: 0x200000010
+
+; CHECK: Note: extra DXIL module flags:
+; CHECK:       Raw and Structured buffers
+; CHECK:       Any UAV may not alias any other UAV
+;
+
+; CHECK: Function loadUAV : 0x20000000
+define float @loadUAV() #0 {
+  %res = call target("dx.TypedBuffer", float, 1, 0, 0)
+      @llvm.dx.resource.handlefrombinding(i32 0, i32 0, i32 1, i32 0, i1 false)
+  %load = call {float, i1} @llvm.dx.resource.load.typedbuffer(
+      target("dx.TypedBuffer", float, 1, 0, 0) %res, i32 0)
+  %val = extractvalue {float, i1} %load, 0
+  ret float %val
+}
+
+; CHECK: Function loadSRV : 0x00000010
+define float @loadSRV() #0 {
+  %res = tail call target("dx.RawBuffer", float, 0, 0)
+      @llvm.dx.resource.handlefrombinding(i32 0, i32 0, i32 1, i32 0, i1 false)
+  %load = call {float, i1} @llvm.dx.resource.load.rawbuffer(
+      target("dx.RawBuffer", float, 0, 0) %res, i32 0, i32 0)
+  %val = extractvalue { float, i1 } %load, 0
+  ret float %val
+}
+
+attributes #0 = { convergent norecurse nounwind "hlsl.export"}
diff --git a/llvm/test/CodeGen/DirectX/ShaderFlags/typed-uav-load-additional-formats.ll b/llvm/test/CodeGen/DirectX/ShaderFlags/typed-uav-load-additional-formats.ll
index 060d54f961c70..96f80f531fa32 100644
--- a/llvm/test/CodeGen/DirectX/ShaderFlags/typed-uav-load-additional-formats.ll
+++ b/llvm/test/CodeGen/DirectX/ShaderFlags/typed-uav-load-additional-formats.ll
@@ -8,12 +8,13 @@ target triple = "dxil-pc-shadermodel6.7-library"
 ; CHECK-OBJ:     TypedUAVLoadAdditionalFormats: true
 
 ; CHECK:      Combined Shader Flags for Module
-; CHECK-NEXT: Shader Flags Value: 0x00002000
+; CHECK-NEXT: Shader Flags Value: 0x200002000
 
 ; CHECK: Note: shader requires additional functionality:
 ; CHECK:       Typed UAV Load Additional Formats
+; CHECK:       Any UAV may not alias any other UAV
 
-; CHECK: Function multicomponent : 0x00002000
+; CHECK: Function multicomponent : 0x200002000
 define <4 x float> @multicomponent() #0 {
   %res = call target("dx.TypedBuffer", <4 x float>, 1, 0, 0)
       @llvm.dx.resource.handlefrombinding(i32 0, i32 0, i32 1, i32 0, i1 false)
@@ -23,7 +24,7 @@ define <4 x float> @multicomponent() #0 {
   ret <4 x float> %val
 }
 
-; CHECK: Function onecomponent : 0x00000000
+; CHECK: Function onecomponent : 0x200000000
 define float @onecomponent() #0 {
   %res = call target("dx.TypedBuffer", float, 1, 0, 0)
       @llvm.dx.resource.handlefrombinding(i32 0, i32 0, i32 1, i32 0, i1 false)
@@ -33,7 +34,7 @@ define float @onecomponent() #0 {
   ret float %val
 }
 
-; CHECK: Function noload : 0x00000000
+; CHECK: Function noload : 0x200000000
 define void @noload(<4 x float> %val) #0 {
   %res = call target("dx.TypedBuffer", <4 x float>, 1, 0, 0)
       @llvm.dx.resource.handlefrombinding(i32 0, i32 0, i32 1, i32 0, i1 false)

@llvmbot
Copy link
Member

llvmbot commented Mar 14, 2025

@llvm/pr-subscribers-clang-codegen

Author: Deric C. (Icohedron)

Changes

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:
    • CASE 1: command-line option -res-may-alias is NOT specified AND DXIL Version > 1.7 AND function uses UAVs
    • CASE 2: command-line option -res-may-alias is NOT specified AND DXIL Version <= 1.7 AND UAVs present globally
  • Add tests
    • A test (res-may-not-alias-shadermodel6.8.ll) for CASE 1
    • A test (res-may-not-alias-shadermodel6.7.ll) for CASE 2
    • A frontend test (res-may-alias.hlsl) for testing that the command-line option -res-may-alias sets the module metadata flag dx.resmayalias to 1, and does not set the module metadata flag dx.resmayalias if -res-may-alias is not given
    • 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

Full diff: https://github.com/llvm/llvm-project/pull/131070.diff

12 Files Affected:

  • (modified) clang/include/clang/Basic/CodeGenOptions.def (+3)
  • (modified) clang/include/clang/Driver/Options.td (+5)
  • (modified) clang/lib/CodeGen/CGHLSLRuntime.cpp (+3)
  • (modified) clang/lib/Driver/ToolChains/Clang.cpp (+1)
  • (added) clang/test/CodeGenHLSL/res-may-alias.hlsl (+7)
  • (modified) llvm/lib/Target/DirectX/DXILShaderFlags.cpp (+37-6)
  • (modified) llvm/lib/Target/DirectX/DXILShaderFlags.h (+7-2)
  • (added) llvm/test/CodeGen/DirectX/ShaderFlags/res-may-alias-0.ll (+39)
  • (added) llvm/test/CodeGen/DirectX/ShaderFlags/res-may-alias-1.ll (+37)
  • (added) llvm/test/CodeGen/DirectX/ShaderFlags/res-may-not-alias-shadermodel6.7.ll (+33)
  • (added) llvm/test/CodeGen/DirectX/ShaderFlags/res-may-not-alias-shadermodel6.8.ll (+33)
  • (modified) llvm/test/CodeGen/DirectX/ShaderFlags/typed-uav-load-additional-formats.ll (+5-4)
diff --git a/clang/include/clang/Basic/CodeGenOptions.def b/clang/include/clang/Basic/CodeGenOptions.def
index a7f5f1abbb825..a436c0ec98d5b 100644
--- a/clang/include/clang/Basic/CodeGenOptions.def
+++ b/clang/include/clang/Basic/CodeGenOptions.def
@@ -476,6 +476,9 @@ CODEGENOPT(ImportCallOptimization, 1, 0)
 /// (BlocksRuntime) on Windows.
 CODEGENOPT(StaticClosure, 1, 0)
 
+/// Assume that UAVs/SRVs may alias
+CODEGENOPT(ResMayAlias, 1, 0)
+
 /// FIXME: Make DebugOptions its own top-level .def file.
 #include "DebugOptions.def"
 
diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index 66ae8f1c7f064..9c5fd2354f95e 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -9043,6 +9043,11 @@ def dxil_validator_version : Option<["/", "-"], "validator-version", KIND_SEPARA
   HelpText<"Override validator version for module. Format: <major.minor>;"
            "Default: DXIL.dll version or current internal version">,
   MarshallingInfoString<TargetOpts<"DxilValidatorVersion">, "\"1.8\"">;
+def res_may_alias : Option<["/", "-"], "res-may-alias", KIND_FLAG>,
+  Group<dxc_Group>, Flags<[HelpHidden]>,
+  Visibility<[DXCOption, ClangOption, CC1Option]>,
+  HelpText<"Assume that UAVs/SRVs may alias">,
+  MarshallingInfoFlag<CodeGenOpts<"ResMayAlias">>;
 def target_profile : DXCJoinedOrSeparate<"T">, MetaVarName<"<profile>">,
   HelpText<"Set target profile">,
   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,"
diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp b/clang/lib/CodeGen/CGHLSLRuntime.cpp
index 5916fa6183a27..6fd8bc295e8ca 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.cpp
+++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp
@@ -283,10 +283,13 @@ void CGHLSLRuntime::addHLSLBufferLayoutType(const RecordType *StructType,
 
 void CGHLSLRuntime::finishCodeGen() {
   auto &TargetOpts = CGM.getTarget().getTargetOpts();
+  auto &CodeGenOpts = CGM.getCodeGenOpts();
   llvm::Module &M = CGM.getModule();
   Triple T(M.getTargetTriple());
   if (T.getArch() == Triple::ArchType::dxil)
     addDxilValVersion(TargetOpts.DxilValidatorVersion, M);
+  if (CodeGenOpts.ResMayAlias)
+    M.setModuleFlag(llvm::Module::ModFlagBehavior::Error, "dx.resmayalias", 1);
 
   generateGlobalCtorDtorCalls();
 }
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index fe172d923ac07..9be3939641cfc 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -3959,6 +3959,7 @@ static void RenderOpenCLOptions(const ArgList &Args, ArgStringList &CmdArgs,
 static void RenderHLSLOptions(const ArgList &Args, ArgStringList &CmdArgs,
                               types::ID InputType) {
   const unsigned ForwardedArguments[] = {options::OPT_dxil_validator_version,
+                                         options::OPT_res_may_alias,
                                          options::OPT_D,
                                          options::OPT_I,
                                          options::OPT_O,
diff --git a/clang/test/CodeGenHLSL/res-may-alias.hlsl b/clang/test/CodeGenHLSL/res-may-alias.hlsl
new file mode 100644
index 0000000000000..53ee8ee4935d8
--- /dev/null
+++ b/clang/test/CodeGenHLSL/res-may-alias.hlsl
@@ -0,0 +1,7 @@
+// RUN: %clang_cc1 -res-may-alias -finclude-default-header -triple dxil-pc-shadermodel6.3-library -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s --check-prefix=FLAG
+// RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.3-library -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s --check-prefix=NOFLAG
+
+// FLAG-DAG: ![[RMA:.*]] = !{i32 1, !"dx.resmayalias", i32 1}
+// FLAG-DAG: !llvm.module.flags = !{{{.*}}![[RMA]]{{.*}}}
+
+// NOFLAG-NOT: dx.resmayalias
diff --git a/llvm/lib/Target/DirectX/DXILShaderFlags.cpp b/llvm/lib/Target/DirectX/DXILShaderFlags.cpp
index 31fbd66dfaa2d..b05ee53798524 100644
--- a/llvm/lib/Target/DirectX/DXILShaderFlags.cpp
+++ b/llvm/lib/Target/DirectX/DXILShaderFlags.cpp
@@ -74,7 +74,8 @@ static bool checkWaveOps(Intrinsic::ID IID) {
 /// \param I Instruction to check.
 void ModuleShaderFlags::updateFunctionFlags(ComputedShaderFlags &CSF,
                                             const Instruction &I,
-                                            DXILResourceTypeMap &DRTM) {
+                                            DXILResourceTypeMap &DRTM,
+                                            const ModuleMetadataInfo &MMDI) {
   if (!CSF.Doubles)
     CSF.Doubles = I.getType()->isDoubleTy();
 
@@ -116,8 +117,17 @@ void ModuleShaderFlags::updateFunctionFlags(ComputedShaderFlags &CSF,
     switch (II->getIntrinsicID()) {
     default:
       break;
-    case Intrinsic::dx_resource_handlefrombinding:
-      switch (DRTM[cast<TargetExtType>(II->getType())].getResourceKind()) {
+    case Intrinsic::dx_resource_handlefrombinding: {
+      dxil::ResourceTypeInfo &RTI = DRTM[cast<TargetExtType>(II->getType())];
+
+      // If -res-may-alias is NOT specified, and DXIL Ver > 1.7.
+      // Then set ResMayNotAlias if function uses UAVs.
+      if (!CSF.ResMayNotAlias && !ResMayAlias &&
+          MMDI.DXILVersion > VersionTuple(1, 7) && RTI.isUAV()) {
+        CSF.ResMayNotAlias = true;
+      }
+
+      switch (RTI.getResourceKind()) {
       case dxil::ResourceKind::StructuredBuffer:
       case dxil::ResourceKind::RawBuffer:
         CSF.EnableRawAndStructuredBuffers = true;
@@ -126,6 +136,7 @@ void ModuleShaderFlags::updateFunctionFlags(ComputedShaderFlags &CSF,
         break;
       }
       break;
+    }
     case Intrinsic::dx_resource_load_typedbuffer: {
       dxil::ResourceTypeInfo &RTI =
           DRTM[cast<TargetExtType>(II->getArgOperand(0)->getType())];
@@ -151,7 +162,17 @@ void ModuleShaderFlags::updateFunctionFlags(ComputedShaderFlags &CSF,
 
 /// Construct ModuleShaderFlags for module Module M
 void ModuleShaderFlags::initialize(Module &M, DXILResourceTypeMap &DRTM,
+                                   DXILBindingMap &DBM,
                                    const ModuleMetadataInfo &MMDI) {
+
+  // Check if -res-may-alias was provided on the command line.
+  // The command line option will set the dx.resmayalias module flag to 1.
+  if (auto *RMA = mdconst::extract_or_null<ConstantInt>(
+          M.getModuleFlag("dx.resmayalias"))) {
+    if (RMA->getValue() != 0)
+      ResMayAlias = true;
+  }
+
   CallGraph CG(M);
 
   // Compute Shader Flags Mask for all functions using post-order visit of SCC
@@ -176,10 +197,16 @@ void ModuleShaderFlags::initialize(Module &M, DXILResourceTypeMap &DRTM,
         continue;
       }
 
+      // If -res-may-alias is NOT specified, and DXIL Ver <= 1.7.
+      // Then set ResMayNotAlias to true if there are UAVs present globally.
+      if (!ResMayAlias && MMDI.DXILVersion <= VersionTuple(1, 7)) {
+        SCCSF.ResMayNotAlias = !DBM.uavs().empty();
+      }
+
       ComputedShaderFlags CSF;
       for (const auto &BB : *F)
         for (const auto &I : BB)
-          updateFunctionFlags(CSF, I, DRTM);
+          updateFunctionFlags(CSF, I, DRTM, MMDI);
       // Update combined shader flags mask for all functions in this SCC
       SCCSF.merge(CSF);
 
@@ -249,10 +276,11 @@ AnalysisKey ShaderFlagsAnalysis::Key;
 ModuleShaderFlags ShaderFlagsAnalysis::run(Module &M,
                                            ModuleAnalysisManager &AM) {
   DXILResourceTypeMap &DRTM = AM.getResult<DXILResourceTypeAnalysis>(M);
+  DXILBindingMap &DBM = AM.getResult<DXILResourceBindingAnalysis>(M);
   const ModuleMetadataInfo MMDI = AM.getResult<DXILMetadataAnalysis>(M);
 
   ModuleShaderFlags MSFI;
-  MSFI.initialize(M, DRTM, MMDI);
+  MSFI.initialize(M, DRTM, DBM, MMDI);
 
   return MSFI;
 }
@@ -282,16 +310,19 @@ PreservedAnalyses ShaderFlagsAnalysisPrinter::run(Module &M,
 bool ShaderFlagsAnalysisWrapper::runOnModule(Module &M) {
   DXILResourceTypeMap &DRTM =
       getAnalysis<DXILResourceTypeWrapperPass>().getResourceTypeMap();
+  DXILBindingMap &DBM =
+      getAnalysis<DXILResourceBindingWrapperPass>().getBindingMap();
   const ModuleMetadataInfo MMDI =
       getAnalysis<DXILMetadataAnalysisWrapperPass>().getModuleMetadata();
 
-  MSFI.initialize(M, DRTM, MMDI);
+  MSFI.initialize(M, DRTM, DBM, MMDI);
   return false;
 }
 
 void ShaderFlagsAnalysisWrapper::getAnalysisUsage(AnalysisUsage &AU) const {
   AU.setPreservesAll();
   AU.addRequiredTransitive<DXILResourceTypeWrapperPass>();
+  AU.addRequiredTransitive<DXILResourceBindingWrapperPass>();
   AU.addRequired<DXILMetadataAnalysisWrapperPass>();
 }
 
diff --git a/llvm/lib/Target/DirectX/DXILShaderFlags.h b/llvm/lib/Target/DirectX/DXILShaderFlags.h
index abf7cc86259ed..b47c79cb293a5 100644
--- a/llvm/lib/Target/DirectX/DXILShaderFlags.h
+++ b/llvm/lib/Target/DirectX/DXILShaderFlags.h
@@ -28,6 +28,7 @@ namespace llvm {
 class Module;
 class GlobalVariable;
 class DXILResourceTypeMap;
+class DXILBindingMap;
 
 namespace dxil {
 
@@ -84,12 +85,16 @@ struct ComputedShaderFlags {
 };
 
 struct ModuleShaderFlags {
-  void initialize(Module &, DXILResourceTypeMap &DRTM,
+  void initialize(Module &, DXILResourceTypeMap &DRTM, DXILBindingMap &DBM,
                   const ModuleMetadataInfo &MMDI);
   const ComputedShaderFlags &getFunctionFlags(const Function *) const;
   const ComputedShaderFlags &getCombinedFlags() const { return CombinedSFMask; }
 
 private:
+  // A bool to indicate if the -res-may-alias flag was passed to clang-dxc.
+  // A module flag "dx.resmayalias" is set to 1 if true.
+  // This bool is used in the logic for setting the flag ResMayNotAlias.
+  bool ResMayAlias = false;
   /// Map of Function-Shader Flag Mask pairs representing properties of each of
   /// the functions in the module. Shader Flags of each function represent both
   /// module-level and function-level flags
@@ -97,7 +102,7 @@ struct ModuleShaderFlags {
   /// Combined Shader Flag Mask of all functions of the module
   ComputedShaderFlags CombinedSFMask{};
   void updateFunctionFlags(ComputedShaderFlags &, const Instruction &,
-                           DXILResourceTypeMap &);
+                           DXILResourceTypeMap &, const ModuleMetadataInfo &);
 };
 
 class ShaderFlagsAnalysis : public AnalysisInfoMixin<ShaderFlagsAnalysis> {
diff --git a/llvm/test/CodeGen/DirectX/ShaderFlags/res-may-alias-0.ll b/llvm/test/CodeGen/DirectX/ShaderFlags/res-may-alias-0.ll
new file mode 100644
index 0000000000000..29901de7f8e37
--- /dev/null
+++ b/llvm/test/CodeGen/DirectX/ShaderFlags/res-may-alias-0.ll
@@ -0,0 +1,39 @@
+; RUN: opt -S --passes="print-dx-shader-flags" 2>&1 %s | FileCheck %s
+
+target triple = "dxil-pc-shadermodel6.8-library"
+
+; CHECK:      Combined Shader Flags for Module
+; CHECK-NEXT: Shader Flags Value: 0x200000010
+
+; CHECK: Note: extra DXIL module flags:
+; CHECK:       Raw and Structured buffers
+; CHECK:       Any UAV may not alias any other UAV
+;
+
+; CHECK: Function loadUAV : 0x20000000
+define float @loadUAV() #0 {
+  %res = call target("dx.TypedBuffer", float, 1, 0, 0)
+      @llvm.dx.resource.handlefrombinding(i32 0, i32 0, i32 1, i32 0, i1 false)
+  %load = call {float, i1} @llvm.dx.resource.load.typedbuffer(
+      target("dx.TypedBuffer", float, 1, 0, 0) %res, i32 0)
+  %val = extractvalue {float, i1} %load, 0
+  ret float %val
+}
+
+; CHECK: Function loadSRV : 0x00000010
+define float @loadSRV() #0 {
+  %res = tail call target("dx.RawBuffer", float, 0, 0)
+      @llvm.dx.resource.handlefrombinding(i32 0, i32 0, i32 1, i32 0, i1 false)
+  %load = call {float, i1} @llvm.dx.resource.load.rawbuffer(
+      target("dx.RawBuffer", float, 0, 0) %res, i32 0, i32 0)
+  %val = extractvalue { float, i1 } %load, 0
+  ret float %val
+}
+
+!llvm.module.flags = !{!0}
+
+; dx.resmayalias should never appear with a value of 0.
+; But if it does, ensure that it has no effect.
+!0 = !{i32 1, !"dx.resmayalias", i32 0}
+
+attributes #0 = { convergent norecurse nounwind "hlsl.export"}
diff --git a/llvm/test/CodeGen/DirectX/ShaderFlags/res-may-alias-1.ll b/llvm/test/CodeGen/DirectX/ShaderFlags/res-may-alias-1.ll
new file mode 100644
index 0000000000000..98a8dd06f6020
--- /dev/null
+++ b/llvm/test/CodeGen/DirectX/ShaderFlags/res-may-alias-1.ll
@@ -0,0 +1,37 @@
+; RUN: opt -S --passes="print-dx-shader-flags" 2>&1 %s | FileCheck %s
+
+target triple = "dxil-pc-shadermodel6.8-library"
+
+; CHECK:      Combined Shader Flags for Module
+; CHECK-NEXT: Shader Flags Value: 0x00000010
+
+; CHECK: Note: extra DXIL module flags:
+; CHECK:       Raw and Structured buffers
+; CHECK-NOT:   Any UAV may not alias any other UAV
+;
+
+; CHECK: Function loadUAV : 0x00000000
+define float @loadUAV() #0 {
+  %res = call target("dx.TypedBuffer", float, 1, 0, 0)
+      @llvm.dx.resource.handlefrombinding(i32 0, i32 0, i32 1, i32 0, i1 false)
+  %load = call {float, i1} @llvm.dx.resource.load.typedbuffer(
+      target("dx.TypedBuffer", float, 1, 0, 0) %res, i32 0)
+  %val = extractvalue {float, i1} %load, 0
+  ret float %val
+}
+
+; CHECK: Function loadSRV : 0x00000010
+define float @loadSRV() #0 {
+  %res = tail call target("dx.RawBuffer", float, 0, 0)
+      @llvm.dx.resource.handlefrombinding(i32 0, i32 0, i32 1, i32 0, i1 false)
+  %load = call {float, i1} @llvm.dx.resource.load.rawbuffer(
+      target("dx.RawBuffer", float, 0, 0) %res, i32 0, i32 0)
+  %val = extractvalue { float, i1 } %load, 0
+  ret float %val
+}
+
+!llvm.module.flags = !{!0}
+
+!0 = !{i32 1, !"dx.resmayalias", i32 1}
+
+attributes #0 = { convergent norecurse nounwind "hlsl.export"}
diff --git a/llvm/test/CodeGen/DirectX/ShaderFlags/res-may-not-alias-shadermodel6.7.ll b/llvm/test/CodeGen/DirectX/ShaderFlags/res-may-not-alias-shadermodel6.7.ll
new file mode 100644
index 0000000000000..ab3eea71bf8f0
--- /dev/null
+++ b/llvm/test/CodeGen/DirectX/ShaderFlags/res-may-not-alias-shadermodel6.7.ll
@@ -0,0 +1,33 @@
+; RUN: opt -S --passes="print-dx-shader-flags" 2>&1 %s | FileCheck %s
+
+target triple = "dxil-pc-shadermodel6.7-library"
+
+; CHECK:      Combined Shader Flags for Module
+; CHECK-NEXT: Shader Flags Value: 0x200000010
+
+; CHECK: Note: extra DXIL module flags:
+; CHECK:       Raw and Structured buffers
+; CHECK:       Any UAV may not alias any other UAV
+;
+
+; CHECK: Function loadUAV : 0x200000000
+define float @loadUAV() #0 {
+  %res = call target("dx.TypedBuffer", float, 1, 0, 0)
+      @llvm.dx.resource.handlefrombinding(i32 0, i32 0, i32 1, i32 0, i1 false)
+  %load = call {float, i1} @llvm.dx.resource.load.typedbuffer(
+      target("dx.TypedBuffer", float, 1, 0, 0) %res, i32 0)
+  %val = extractvalue {float, i1} %load, 0
+  ret float %val
+}
+
+; CHECK: Function loadSRV : 0x200000010
+define float @loadSRV() #0 {
+  %res = tail call target("dx.RawBuffer", float, 0, 0)
+      @llvm.dx.resource.handlefrombinding(i32 0, i32 0, i32 1, i32 0, i1 false)
+  %load = call {float, i1} @llvm.dx.resource.load.rawbuffer(
+      target("dx.RawBuffer", float, 0, 0) %res, i32 0, i32 0)
+  %val = extractvalue { float, i1 } %load, 0
+  ret float %val
+}
+
+attributes #0 = { convergent norecurse nounwind "hlsl.export"}
diff --git a/llvm/test/CodeGen/DirectX/ShaderFlags/res-may-not-alias-shadermodel6.8.ll b/llvm/test/CodeGen/DirectX/ShaderFlags/res-may-not-alias-shadermodel6.8.ll
new file mode 100644
index 0000000000000..fb5e234f0bd93
--- /dev/null
+++ b/llvm/test/CodeGen/DirectX/ShaderFlags/res-may-not-alias-shadermodel6.8.ll
@@ -0,0 +1,33 @@
+; RUN: opt -S --passes="print-dx-shader-flags" 2>&1 %s | FileCheck %s
+
+target triple = "dxil-pc-shadermodel6.8-library"
+
+; CHECK:      Combined Shader Flags for Module
+; CHECK-NEXT: Shader Flags Value: 0x200000010
+
+; CHECK: Note: extra DXIL module flags:
+; CHECK:       Raw and Structured buffers
+; CHECK:       Any UAV may not alias any other UAV
+;
+
+; CHECK: Function loadUAV : 0x20000000
+define float @loadUAV() #0 {
+  %res = call target("dx.TypedBuffer", float, 1, 0, 0)
+      @llvm.dx.resource.handlefrombinding(i32 0, i32 0, i32 1, i32 0, i1 false)
+  %load = call {float, i1} @llvm.dx.resource.load.typedbuffer(
+      target("dx.TypedBuffer", float, 1, 0, 0) %res, i32 0)
+  %val = extractvalue {float, i1} %load, 0
+  ret float %val
+}
+
+; CHECK: Function loadSRV : 0x00000010
+define float @loadSRV() #0 {
+  %res = tail call target("dx.RawBuffer", float, 0, 0)
+      @llvm.dx.resource.handlefrombinding(i32 0, i32 0, i32 1, i32 0, i1 false)
+  %load = call {float, i1} @llvm.dx.resource.load.rawbuffer(
+      target("dx.RawBuffer", float, 0, 0) %res, i32 0, i32 0)
+  %val = extractvalue { float, i1 } %load, 0
+  ret float %val
+}
+
+attributes #0 = { convergent norecurse nounwind "hlsl.export"}
diff --git a/llvm/test/CodeGen/DirectX/ShaderFlags/typed-uav-load-additional-formats.ll b/llvm/test/CodeGen/DirectX/ShaderFlags/typed-uav-load-additional-formats.ll
index 060d54f961c70..96f80f531fa32 100644
--- a/llvm/test/CodeGen/DirectX/ShaderFlags/typed-uav-load-additional-formats.ll
+++ b/llvm/test/CodeGen/DirectX/ShaderFlags/typed-uav-load-additional-formats.ll
@@ -8,12 +8,13 @@ target triple = "dxil-pc-shadermodel6.7-library"
 ; CHECK-OBJ:     TypedUAVLoadAdditionalFormats: true
 
 ; CHECK:      Combined Shader Flags for Module
-; CHECK-NEXT: Shader Flags Value: 0x00002000
+; CHECK-NEXT: Shader Flags Value: 0x200002000
 
 ; CHECK: Note: shader requires additional functionality:
 ; CHECK:       Typed UAV Load Additional Formats
+; CHECK:       Any UAV may not alias any other UAV
 
-; CHECK: Function multicomponent : 0x00002000
+; CHECK: Function multicomponent : 0x200002000
 define <4 x float> @multicomponent() #0 {
   %res = call target("dx.TypedBuffer", <4 x float>, 1, 0, 0)
       @llvm.dx.resource.handlefrombinding(i32 0, i32 0, i32 1, i32 0, i1 false)
@@ -23,7 +24,7 @@ define <4 x float> @multicomponent() #0 {
   ret <4 x float> %val
 }
 
-; CHECK: Function onecomponent : 0x00000000
+; CHECK: Function onecomponent : 0x200000000
 define float @onecomponent() #0 {
   %res = call target("dx.TypedBuffer", float, 1, 0, 0)
       @llvm.dx.resource.handlefrombinding(i32 0, i32 0, i32 1, i32 0, i1 false)
@@ -33,7 +34,7 @@ define float @onecomponent() #0 {
   ret float %val
 }
 
-; CHECK: Function noload : 0x00000000
+; CHECK: Function noload : 0x200000000
 define void @noload(<4 x float> %val) #0 {
   %res = call target("dx.TypedBuffer", <4 x float>, 1, 0, 0)
       @llvm.dx.resource.handlefrombinding(i32 0, i32 0, i32 1, i32 0, i1 false)

Copy link
Contributor

@inbelic inbelic left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice work, just some minor comments/questions.

As mentioned, we should have a definitive answer to if we need SRV to be included at all here (both in code comments and testcases).

target triple = "dxil-pc-shadermodel6.8-library"

; CHECK: Combined Shader Flags for Module
; CHECK-NEXT: Shader Flags Value: 0x200000010
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems the ResMayNotAlias flag is what we are checking and is the 2 value. What is the 1 value for?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The 1 is for the structured buffer (SRV) in the same module. It's there so I can test that the function that accesses only an SRV will not get the ResMayNotAlias flag.


; dx.resmayalias should never appear with a value of 0.
; But if it does, ensure that it has no effect.
!0 = !{i32 1, !"dx.resmayalias", i32 0}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the moment we define some metadata we should expect that some user may set the field manually, so having tests for this should definitely be included

Copy link
Member

@farzonl farzonl left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@Icohedron Icohedron merged commit 727f392 into llvm:main Apr 10, 2025
11 of 12 checks passed
var-const pushed a commit to ldionne/llvm-project that referenced this pull request Apr 17, 2025
…1070)

Fixes llvm#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
@damyanp damyanp moved this to Closed in HLSL Support Apr 25, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
backend:DirectX clang:codegen IR generation bugs: mangling, exceptions, etc. clang:driver 'clang' and 'clang++' user-facing binaries. Not 'clang-cl' clang:frontend Language frontend issues, e.g. anything involving "Sema" clang Clang issues not falling into any other category HLSL HLSL Language Support
Projects
Status: Closed
Development

Successfully merging this pull request may close these issues.

[DirectX] Shader Flags Analysis for ResMayNotAlias
4 participants