[DX] Add analysis and printer for shader flags
authorChris Bieneman <chris.bieneman@me.com>
Tue, 11 Oct 2022 17:09:30 +0000 (12:09 -0500)
committerChris Bieneman <chris.bieneman@me.com>
Tue, 11 Oct 2022 19:27:05 +0000 (14:27 -0500)
This adds infrastructural pieces for an analysis to compute the DXIL
shader flags. In this state the analysis can compute two fairly
straightforward feature flags for use of double-precision floating
point values and the DX 11.1 extended double support.

This patch does conflict with D135190, conflicts will be resolved prior
to merging.

Reviewed By: python3kgae

Differential Revision: https://reviews.llvm.org/D135393

# Conflicts:
# llvm/lib/Target/DirectX/CMakeLists.txt
# llvm/lib/Target/DirectX/DirectXTargetMachine.cpp

llvm/lib/Target/DirectX/CMakeLists.txt
llvm/lib/Target/DirectX/DXILShaderFlags.cpp [new file with mode: 0644]
llvm/lib/Target/DirectX/DXILShaderFlags.h [new file with mode: 0644]
llvm/lib/Target/DirectX/DirectXTargetMachine.cpp
llvm/test/CodeGen/DirectX/ShaderFlags/double-extensions.ll [new file with mode: 0644]
llvm/test/CodeGen/DirectX/ShaderFlags/doubles.ll [new file with mode: 0644]
llvm/test/CodeGen/DirectX/ShaderFlags/no_flags.ll [new file with mode: 0644]

index 62e51a5..4079762 100644 (file)
@@ -23,6 +23,7 @@ add_llvm_target(DirectXCodeGen
   DXILPrepare.cpp
   DXILResource.cpp
   DXILResourceAnalysis.cpp
+  DXILShaderFlags.cpp
   DXILTranslateMetadata.cpp
   PointerTypeAnalysis.cpp
 
diff --git a/llvm/lib/Target/DirectX/DXILShaderFlags.cpp b/llvm/lib/Target/DirectX/DXILShaderFlags.cpp
new file mode 100644 (file)
index 0000000..6af3847
--- /dev/null
@@ -0,0 +1,73 @@
+//===- DXILShaderFlags.cpp - DXIL Shader Flags helper objects -------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file This file contains helper objects and APIs for working with DXIL
+///       Shader Flags.
+///
+//===----------------------------------------------------------------------===//
+
+#include "DXILShaderFlags.h"
+#include "DirectX.h"
+#include "llvm/IR/Instruction.h"
+#include "llvm/IR/Module.h"
+#include "llvm/Support/FormatVariadic.h"
+
+using namespace llvm;
+using namespace llvm::dxil;
+
+static void updateFlags(ComputedShaderFlags &Flags, const Instruction &I) {
+  Type *Ty = I.getType();
+  if (Ty->isDoubleTy()) {
+    Flags.Doubles = true;
+    switch (I.getOpcode()) {
+    case Instruction::FDiv:
+    case Instruction::UIToFP:
+    case Instruction::SIToFP:
+    case Instruction::FPToUI:
+    case Instruction::FPToSI:
+      Flags.DX11_1_DoubleExtensions = true;
+      break;
+    }
+  }
+}
+
+ComputedShaderFlags ComputedShaderFlags::computeFlags(Module &M) {
+  ComputedShaderFlags Flags;
+  for (const auto &F : M)
+    for (const auto &BB : F)
+      for (const auto &I : BB)
+        updateFlags(Flags, I);
+  return Flags;
+}
+
+void ComputedShaderFlags::print(raw_ostream &OS) const {
+  uint64_t FlagVal = (uint64_t) * this;
+  OS << formatv("; Shader Flags Value: {0:x8}\n;\n", FlagVal);
+  if (FlagVal == 0)
+    return;
+  OS << "; Note: shader requires additional functionality:\n";
+#define SHADER_FLAG(bit, FlagName, Str)                                        \
+  if (FlagName)                                                                \
+    OS << ";       " Str "\n";
+#include "llvm/BinaryFormat/DXContainerConstants.def"
+  OS << ";\n";
+}
+
+AnalysisKey ShaderFlagsAnalysis::Key;
+
+ComputedShaderFlags ShaderFlagsAnalysis::run(Module &M,
+                                             ModuleAnalysisManager &AM) {
+  return ComputedShaderFlags::computeFlags(M);
+}
+
+PreservedAnalyses ShaderFlagsAnalysisPrinter::run(Module &M,
+                                                  ModuleAnalysisManager &AM) {
+  ComputedShaderFlags Flags = AM.getResult<ShaderFlagsAnalysis>(M);
+  Flags.print(OS);
+  return PreservedAnalyses::all();
+}
diff --git a/llvm/lib/Target/DirectX/DXILShaderFlags.h b/llvm/lib/Target/DirectX/DXILShaderFlags.h
new file mode 100644 (file)
index 0000000..e877594
--- /dev/null
@@ -0,0 +1,79 @@
+//===- DXILShaderFlags.h - DXIL Shader Flags helper objects ---------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file This file contains helper objects and APIs for working with DXIL
+///       Shader Flags.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TARGET_DIRECTX_DXILSHADERFLAGS_H
+#define LLVM_TARGET_DIRECTX_DXILSHADERFLAGS_H
+
+#include "llvm/BinaryFormat/DXContainer.h"
+#include "llvm/IR/PassManager.h"
+#include "llvm/Pass.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cstdint>
+
+namespace llvm {
+class Module;
+class GlobalVariable;
+
+namespace dxil {
+
+struct ComputedShaderFlags {
+#define SHADER_FLAG(bit, FlagName, Str) bool FlagName : 1;
+#include "llvm/BinaryFormat/DXContainerConstants.def"
+
+#define SHADER_FLAG(bit, FlagName, Str) FlagName = false;
+  ComputedShaderFlags() {
+#include "llvm/BinaryFormat/DXContainerConstants.def"
+  }
+
+  operator uint64_t() const {
+    uint64_t FlagValue = 0;
+#define SHADER_FLAG(bit, FlagName, Str)                                        \
+  FlagValue |=                                                                 \
+      FlagName ? static_cast<uint64_t>(dxbc::FeatureFlags::FlagName) : 0ull;
+#include "llvm/BinaryFormat/DXContainerConstants.def"
+    return FlagValue;
+  }
+
+  static ComputedShaderFlags computeFlags(Module &M);
+  void print(raw_ostream &OS = dbgs()) const;
+  LLVM_DUMP_METHOD void dump() const { print(); }
+};
+
+class ShaderFlagsAnalysis : public AnalysisInfoMixin<ShaderFlagsAnalysis> {
+  friend AnalysisInfoMixin<ShaderFlagsAnalysis>;
+  static AnalysisKey Key;
+
+public:
+  ShaderFlagsAnalysis() = default;
+
+  using Result = ComputedShaderFlags;
+
+  ComputedShaderFlags run(Module &M, ModuleAnalysisManager &AM);
+};
+
+/// Printer pass for ShaderFlagsAnalysis results.
+class ShaderFlagsAnalysisPrinter
+    : public PassInfoMixin<ShaderFlagsAnalysisPrinter> {
+  raw_ostream &OS;
+
+public:
+  explicit ShaderFlagsAnalysisPrinter(raw_ostream &OS) : OS(OS) {}
+  PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM);
+};
+
+} // namespace dxil
+} // namespace llvm
+
+#endif // LLVM_TARGET_DIRECTX_DXILSHADERFLAGS_H
index 81aaf86..c435ca6 100644 (file)
@@ -13,6 +13,7 @@
 
 #include "DirectXTargetMachine.h"
 #include "DXILResourceAnalysis.h"
+#include "DXILShaderFlags.h"
 #include "DXILWriter/DXILWriterPass.h"
 #include "DirectX.h"
 #include "DirectXSubtarget.h"
@@ -103,11 +104,16 @@ void DirectXTargetMachine::registerPassBuilderCallbacks(PassBuilder &PB) {
           PM.addPass(DXILResourcePrinterPass(dbgs()));
           return true;
         }
+        if (PassName == "print-dx-shader-flags") {
+          PM.addPass(dxil::ShaderFlagsAnalysisPrinter(dbgs()));
+          return true;
+        }
         return false;
       });
 
   PB.registerAnalysisRegistrationCallback([](ModuleAnalysisManager &MAM) {
     MAM.registerPass([&] { return DXILResourceAnalysis(); });
+    MAM.registerPass([&] { return dxil::ShaderFlagsAnalysis(); });
   });
 }
 
diff --git a/llvm/test/CodeGen/DirectX/ShaderFlags/double-extensions.ll b/llvm/test/CodeGen/DirectX/ShaderFlags/double-extensions.ll
new file mode 100644 (file)
index 0000000..4eba4f2
--- /dev/null
@@ -0,0 +1,13 @@
+; RUN: opt -S --passes="print-dx-shader-flags" 2>&1 %s | FileCheck %s
+
+target triple = "dxil-pc-shadermodel6.7-library"
+
+; CHECK: ; Shader Flags Value: 0x00000021
+; CHECK: ; Note: shader requires additional functionality:
+; CHECK-NEXT: ;       Double-precision floating point
+; CHECK-NEXT: ;       Double-precision extensions for 11.1
+; CHECK-NEXT: {{^;$}}
+define double @div(double %a, double %b) {
+  %res = fdiv double %a, %b
+  ret double %res
+}
diff --git a/llvm/test/CodeGen/DirectX/ShaderFlags/doubles.ll b/llvm/test/CodeGen/DirectX/ShaderFlags/doubles.ll
new file mode 100644 (file)
index 0000000..01ba14b
--- /dev/null
@@ -0,0 +1,12 @@
+; RUN: opt -S --passes="print-dx-shader-flags" 2>&1 %s | FileCheck %s
+
+target triple = "dxil-pc-shadermodel6.7-library"
+
+; CHECK: ; Shader Flags Value: 0x00000001
+; CHECK: ; Note: shader requires additional functionality:
+; CHECK-NEXT: ;       Double-precision floating point
+; CHECK-NEXT: {{^;$}}
+define double @add(double %a, double %b) {
+  %sum = fadd double %a, %b
+  ret double %sum
+}
diff --git a/llvm/test/CodeGen/DirectX/ShaderFlags/no_flags.ll b/llvm/test/CodeGen/DirectX/ShaderFlags/no_flags.ll
new file mode 100644 (file)
index 0000000..f7baa1b
--- /dev/null
@@ -0,0 +1,9 @@
+; RUN: opt -S --passes="print-dx-shader-flags" 2>&1 %s | FileCheck %s
+
+target triple = "dxil-pc-shadermodel6.7-library"
+
+; CHECK: ; Shader Flags Value: 0x00000000
+define i32 @add(i32 %a, i32 %b) {
+  %sum = add i32 %a, %b
+  ret i32 %sum
+}