瀏覽代碼

Add a pass to eliminate dynamic indexing on output. (#287)

1. Add a pass to eliminate dynamic indexing on output.
2. Fix issue in AllocateSemanticIndex where argIdx should only udpate for leaf node.
Xiang Li 8 年之前
父節點
當前提交
8ce48081cf

+ 2 - 0
include/dxc/HLSL/DxilGenerationPass.h

@@ -38,6 +38,7 @@ namespace llvm {
 /// \brief Create and return a pass that tranform the module into a DXIL module
 /// Note that this pass is designed for use with the legacy pass manager.
 ModulePass *createDxilCondenseResourcesPass();
+ModulePass *createDxilEliminateOutputDynamicIndexingPass();
 ModulePass *createDxilGenerationPass(bool NotOptimized, hlsl::HLSLExtensionsCodegenHelper *extensionsHelper);
 ModulePass *createHLEmitMetadataPass();
 ModulePass *createHLEnsureMetadataPass();
@@ -51,6 +52,7 @@ FunctionPass *createDxilLegalizeSampleOffsetPass();
 FunctionPass *createSimplifyInstPass();
 
 void initializeDxilCondenseResourcesPass(llvm::PassRegistry&);
+void initializeDxilEliminateOutputDynamicIndexingPass(llvm::PassRegistry&);
 void initializeDxilGenerationPassPass(llvm::PassRegistry&);
 void initializeHLEnsureMetadataPass(llvm::PassRegistry&);
 void initializeHLEmitMetadataPass(llvm::PassRegistry&);

+ 1 - 0
lib/HLSL/CMakeLists.txt

@@ -7,6 +7,7 @@ add_llvm_library(LLVMHLSL
   DxilContainer.cpp
   DxilContainerAssembler.cpp
   DxilContainerReflection.cpp
+  DxilEliminateOutputDynamicIndexing.cpp
   DxilGenerationPass.cpp
   DxilInterpolationMode.cpp
   DxilLegalizeSampleOffsetPass.cpp

+ 1 - 0
lib/HLSL/DxcOptimizer.cpp

@@ -81,6 +81,7 @@ HRESULT SetupRegistryPassForHLSL() {
     initializeDSEPass(Registry);
     initializeDeadInstEliminationPass(Registry);
     initializeDxilCondenseResourcesPass(Registry);
+    initializeDxilEliminateOutputDynamicIndexingPass(Registry);
     initializeDxilEmitMetadataPass(Registry);
     initializeDxilGenerationPassPass(Registry);
     initializeDxilLegalizeEvalOperationsPass(Registry);

+ 209 - 0
lib/HLSL/DxilEliminateOutputDynamicIndexing.cpp

@@ -0,0 +1,209 @@
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// DxilEliminateOutputDynamicIndexing.cpp                                    //
+// Copyright (C) Microsoft Corporation. All rights reserved.                 //
+// This file is distributed under the University of Illinois Open Source     //
+// License. See LICENSE.TXT for details.                                     //
+//                                                                           //
+// Eliminate dynamic indexing on output.                                     //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+#include "dxc/HLSL/DxilGenerationPass.h"
+#include "dxc/HLSL/DxilOperations.h"
+#include "dxc/HLSL/DxilSignatureElement.h"
+#include "dxc/HLSL/DxilModule.h"
+#include "dxc/Support/Global.h"
+#include "dxc/HLSL/DxilInstructions.h"
+
+#include "llvm/IR/Module.h"
+#include "llvm/Pass.h"
+#include "llvm/IR/IRBuilder.h"
+#include "llvm/ADT/MapVector.h"
+
+using namespace llvm;
+using namespace hlsl;
+
+namespace {
+class DxilEliminateOutputDynamicIndexing : public ModulePass {
+private:
+
+public:
+  static char ID; // Pass identification, replacement for typeid
+  explicit DxilEliminateOutputDynamicIndexing() : ModulePass(ID) {}
+
+  const char *getPassName() const override {
+    return "DXIL eliminate ouptut dynamic indexing";
+  }
+
+  bool runOnModule(Module &M) override {
+    DxilModule &DM = M.GetOrCreateDxilModule();
+    bool bUpdated = false;
+    if (DM.GetShaderModel()->IsHS()) {
+      hlsl::OP *hlslOP = DM.GetOP();
+      bUpdated = EliminateDynamicOutput(
+          hlslOP, DXIL::OpCode::StorePatchConstant,
+          DM.GetPatchConstantSignature(), DM.GetPatchConstantFunction());
+    }
+
+    // Skip pass thru entry.
+    if (!DM.GetEntryFunction())
+      return bUpdated;
+
+    hlsl::OP *hlslOP = DM.GetOP();
+
+    bUpdated |=
+        EliminateDynamicOutput(hlslOP, DXIL::OpCode::StoreOutput,
+                               DM.GetOutputSignature(), DM.GetEntryFunction());
+
+    return bUpdated;
+  }
+
+private:
+  bool EliminateDynamicOutput(hlsl::OP *hlslOP, DXIL::OpCode opcode, DxilSignature &outputSig, Function *Entry);
+  void ReplaceDynamicOutput(ArrayRef<Value *> tmpSigElts, Value * sigID, Value *zero, Function *F);
+  void StoreTmpSigToOutput(ArrayRef<Value *> tmpSigElts, unsigned row,
+                           Value *opcode, Value *sigID, Function *StoreOutput,
+                           Function *Entry);
+};
+
+// Wrapper for StoreOutput and StorePachConstant which has same signature.
+// void (opcode, sigId, rowIndex, colIndex, value);
+class DxilOutputStore {
+public:
+  const llvm::CallInst *Instr;
+  // Construction and identification
+  DxilOutputStore(llvm::CallInst *pInstr) : Instr(pInstr) {}
+  // Validation support
+  bool isAllowed() const { return true; }
+  bool isArgumentListValid() const {
+    if (5 != llvm::dyn_cast<llvm::CallInst>(Instr)->getNumArgOperands())
+      return false;
+    return true;
+  }
+  // Accessors
+  llvm::Value *get_outputtSigId() const {
+    return Instr->getOperand(DXIL::OperandIndex::kStoreOutputIDOpIdx);
+  }
+  llvm::Value *get_rowIndex() const {
+    return Instr->getOperand(DXIL::OperandIndex::kStoreOutputRowOpIdx);
+  }
+  uint64_t get_colIndex() const {
+    Value *col = Instr->getOperand(DXIL::OperandIndex::kStoreOutputColOpIdx);
+    return cast<ConstantInt>(col)->getLimitedValue();
+  }
+  llvm::Value *get_value() const {
+    return Instr->getOperand(DXIL::OperandIndex::kStoreOutputValOpIdx);
+  }
+};
+
+bool DxilEliminateOutputDynamicIndexing::EliminateDynamicOutput(
+    hlsl::OP *hlslOP, DXIL::OpCode opcode, DxilSignature &outputSig,
+    Function *Entry) {
+  ArrayRef<llvm::Function *> storeOutputs =
+      hlslOP->GetOpFuncList(opcode);
+
+  MapVector<Value *, Type *> dynamicSigSet;
+  for (Function *F : storeOutputs) {
+    // Skip overload not used.
+    if (!F)
+      continue;
+    for (User *U : F->users()) {
+      CallInst *CI = cast<CallInst>(U);
+      DxilOutputStore store(CI);
+      // Save dynamic indeed sigID.
+      if (!isa<ConstantInt>(store.get_rowIndex())) {
+        Value *sigID = store.get_outputtSigId();
+        dynamicSigSet[sigID] = store.get_value()->getType();
+      }
+    }
+  }
+
+  if (dynamicSigSet.empty())
+    return false;
+
+  IRBuilder<> Builder(Entry->getEntryBlock().getFirstInsertionPt());
+
+  Value *opcodeV = Builder.getInt32(static_cast<unsigned>(opcode));
+  Value *zero = Builder.getInt32(0);
+
+  for (auto sig : dynamicSigSet) {
+    Value *sigID = sig.first;
+    Type *EltTy = sig.second;
+    unsigned ID = cast<ConstantInt>(sigID)->getLimitedValue();
+    DxilSignatureElement &sigElt = outputSig.GetElement(ID);
+    unsigned row = sigElt.GetRows();
+    unsigned col = sigElt.GetCols();
+    Type *AT = ArrayType::get(EltTy, row);
+
+    std::vector<Value *> tmpSigElts(col);
+    for (unsigned c = 0; c < col; c++) {
+      Value *newCol = Builder.CreateAlloca(AT);
+      tmpSigElts[c] = newCol;
+    }
+
+    Function *F = hlslOP->GetOpFunc(opcode, EltTy);
+    // Change store output to store tmpSigElts.
+    ReplaceDynamicOutput(tmpSigElts, sigID, zero, F);
+    // Store tmpSigElts to Output before return.
+    StoreTmpSigToOutput(tmpSigElts, row, opcodeV, sigID, F, Entry);
+  }
+  return true;
+}
+
+void DxilEliminateOutputDynamicIndexing::ReplaceDynamicOutput(
+    ArrayRef<Value *> tmpSigElts, Value *sigID, Value *zero, Function *F) {
+  for (auto it = F->user_begin(); it != F->user_end();) {
+    CallInst *CI = cast<CallInst>(*(it++));
+    DxilOutputStore store(CI);
+    if (sigID == store.get_outputtSigId()) {
+      uint64_t col = store.get_colIndex();
+      Value *tmpSigElt = tmpSigElts[col];
+      IRBuilder<> Builder(CI);
+      Value *r = store.get_rowIndex();
+      // Store to tmpSigElt.
+      Value *GEP = Builder.CreateInBoundsGEP(tmpSigElt, {zero, r});
+      Builder.CreateStore(store.get_value(), GEP);
+      // Remove store output.
+      CI->eraseFromParent();
+    }
+  }
+}
+
+void DxilEliminateOutputDynamicIndexing::StoreTmpSigToOutput(
+    ArrayRef<Value *> tmpSigElts, unsigned row, Value *opcode, Value *sigID,
+    Function *StoreOutput, Function *Entry) {
+  Value *args[] = {opcode, sigID, /*row*/ nullptr, /*col*/ nullptr,
+                   /*val*/ nullptr};
+  // Store the tmpSigElts to Output before every return.
+  for (auto &BB : Entry->getBasicBlockList()) {
+    if (ReturnInst *RI = dyn_cast<ReturnInst>(BB.getTerminator())) {
+      IRBuilder<> Builder(RI);
+      Value *zero = Builder.getInt32(0);
+      for (unsigned c = 0; c<tmpSigElts.size(); c++) {
+        Value *col = tmpSigElts[c];
+        args[DXIL::OperandIndex::kStoreOutputColOpIdx] = Builder.getInt8(c);
+        for (unsigned r = 0; r < row; r++) {
+          Value *GEP =
+              Builder.CreateInBoundsGEP(col, {zero, Builder.getInt32(r)});
+          Value *V = Builder.CreateLoad(GEP);
+          args[DXIL::OperandIndex::kStoreOutputRowOpIdx] = Builder.getInt32(r);
+          args[DXIL::OperandIndex::kStoreOutputValOpIdx] = V;
+          Builder.CreateCall(StoreOutput, args);
+        }
+      }
+    }
+  }
+}
+
+}
+
+char DxilEliminateOutputDynamicIndexing::ID = 0;
+
+ModulePass *llvm::createDxilEliminateOutputDynamicIndexingPass() {
+  return new DxilEliminateOutputDynamicIndexing();
+}
+
+INITIALIZE_PASS(DxilEliminateOutputDynamicIndexing,
+                "hlsl-dxil-eliminate-output-dynamic",
+                "DXIL eliminate ouptut dynamic indexing", false, false)

+ 4 - 2
lib/Transforms/Scalar/ScalarReplAggregatesHLSL.cpp

@@ -4057,8 +4057,10 @@ static unsigned AllocateSemanticIndex(
       Type *EltTy = Ty->getStructElementType(i);
       argIdx = AllocateSemanticIndex(EltTy, semIndex, argIdx, endArgIdx,
                                      FlatAnnotationList);
-      // Update argIdx by 1.
-      argIdx++;
+      if (!(EltTy->isStructTy() && !HLMatrixLower::IsMatrixType(EltTy))) {
+        // Update argIdx only when it is a leaf node.
+        argIdx++;
+      }
     }
     return argIdx;
   } else {

+ 23 - 0
tools/clang/test/HLSL/eliminate_dynamic_output.hlsl

@@ -0,0 +1,23 @@
+// RUN: %dxc -Emain -Tvs_6_0 %s | %opt -S -hlsl-dxil-eliminate-output-dynamic | %FileCheck %s
+
+// CHECK-NOT: storeOutput.f32(i32 5, i32 0, i32 %i
+// CHECK: storeOutput.f32(i32 5, i32 0, i32 0
+// CHECK: storeOutput.f32(i32 5, i32 0, i32 1
+// CHECK: storeOutput.f32(i32 5, i32 0, i32 2
+// CHECK: storeOutput.f32(i32 5, i32 0, i32 3
+// CHECK: storeOutput.f32(i32 5, i32 0, i32 4
+// CHECK: storeOutput.f32(i32 5, i32 0, i32 5
+// CHECK: storeOutput.f32(i32 5, i32 0, i32 6
+// CHECK: storeOutput.f32(i32 5, i32 0, i32 7
+
+int  count;
+float4 c[16];
+
+float4 main(out float o[8] : I, float4 pos: POS) : SV_POSITION {
+
+    for (uint i=0;i<count;i++)
+        o[i] = c[i].x;
+
+    return pos;
+}
+

+ 22 - 0
tools/clang/test/HLSL/eliminate_dynamic_output2.hlsl

@@ -0,0 +1,22 @@
+// RUN: %dxc -Emain -Tvs_6_0 %s | %opt -S -hlsl-dxil-eliminate-output-dynamic | %FileCheck %s
+
+// CHECK-NOT: storeOutput.f32(i32 5, i32 0, i32 %i
+// CHECK: storeOutput.f32(i32 5, i32 0, i32 0, i8 0
+// CHECK: storeOutput.f32(i32 5, i32 0, i32 1, i8 0
+// CHECK: storeOutput.f32(i32 5, i32 0, i32 2, i8 0
+// CHECK: storeOutput.f32(i32 5, i32 0, i32 3, i8 0
+// CHECK: storeOutput.f32(i32 5, i32 0, i32 0, i8 1
+// CHECK: storeOutput.f32(i32 5, i32 0, i32 1, i8 1
+// CHECK: storeOutput.f32(i32 5, i32 0, i32 2, i8 1
+// CHECK: storeOutput.f32(i32 5, i32 0, i32 3, i8 1
+int  count;
+float4 c[16];
+
+float4 main(out float2x2 o[2] : I, float4 pos: POS) : SV_POSITION {
+
+    for (uint i=0;i<count;i++)
+        o[i] = c[i].x;
+
+    return pos;
+}
+

+ 24 - 0
tools/clang/test/HLSL/eliminate_dynamic_output3.hlsl

@@ -0,0 +1,24 @@
+// RUN: %dxc -Emain -Tvs_6_0 %s | %opt -S -hlsl-dxil-eliminate-output-dynamic | %FileCheck %s
+
+// CHECK-NOT: storeOutput.f32(i32 5, i32 0, i32 %i
+// CHECK: storeOutput.f32(i32 5, i32 0, i32 0
+// CHECK: storeOutput.f32(i32 5, i32 0, i32 1
+// CHECK: storeOutput.f32(i32 5, i32 0, i32 2
+// CHECK: storeOutput.f32(i32 5, i32 0, i32 3
+// CHECK: storeOutput.f32(i32 5, i32 0, i32 4
+// CHECK: storeOutput.f32(i32 5, i32 0, i32 5
+// CHECK: storeOutput.f32(i32 5, i32 0, i32 6
+// CHECK: storeOutput.f32(i32 5, i32 0, i32 7
+
+int  count;
+float4 c[16];
+
+
+float4 main(out float o[2][2][2] : I, float4 pos: POS) : SV_POSITION {
+
+    for (uint i=0;i<count;i++)
+        o[i][i][i] = c[i].x;
+
+    return pos;
+}
+

+ 34 - 0
tools/clang/test/HLSL/eliminate_dynamic_output4.hlsl

@@ -0,0 +1,34 @@
+// RUN: %dxc -Emain -Tvs_6_0 %s | %opt -S -hlsl-dxil-eliminate-output-dynamic | %FileCheck %s
+
+// CHECK-NOT: storeOutput.f32(i32 5, i32 0, i32 %i
+// CHECK-NOT: storeOutput.f32(i32 5, i32 1, i32 %i
+// CHECK-NOT: storeOutput.f32(i32 5, i32 2, i32 %i
+// CHECK: storeOutput.f32(i32 5, i32 1, i32 0, i8 0
+// CHECK: storeOutput.f32(i32 5, i32 1, i32 1, i8 0
+// CHECK: storeOutput.f32(i32 5, i32 2, i32 0, i8 0
+// CHECK: storeOutput.f32(i32 5, i32 2, i32 1, i8 0
+// CHECK: storeOutput.f32(i32 5, i32 0, i32 0, i8 0
+// CHECK: storeOutput.f32(i32 5, i32 0, i32 1, i8 0
+
+int  count;
+float4 c[16];
+
+struct T {
+   float a;
+};
+
+struct T2 : T {
+  struct T t2;
+  float b;
+};
+
+float4 main(out T2 o[2] : I, float4 pos: POS) : SV_POSITION {
+
+    for (uint i=0;i<count;i++) {
+        o[i].a = c[i].x;
+        o[i].b = c[i].y;
+        o[i].t2.a = c[i].z;
+    }
+    return pos;
+}
+

+ 92 - 0
tools/clang/test/HLSL/eliminate_dynamic_output5.hlsl

@@ -0,0 +1,92 @@
+// RUN: %dxc -E main -T hs_6_0  %s | %opt -S -hlsl-dxil-eliminate-output-dynamic | %FileCheck %s
+
+// CHECK-NOT: storePatchConstant.f32(i32 106, i32 2, i32 %i
+
+
+// CHECK: storePatchConstant.f32(i32 106, i32 2, i32 0, i8 0
+// CHECK: storePatchConstant.f32(i32 106, i32 2, i32 1, i8 0
+// CHECK: storePatchConstant.f32(i32 106, i32 2, i32 2, i8 0
+// CHECK: storePatchConstant.f32(i32 106, i32 2, i32 3, i8 0
+// CHECK: storePatchConstant.f32(i32 106, i32 2, i32 4, i8 0
+// CHECK: storePatchConstant.f32(i32 106, i32 2, i32 5, i8 0
+// CHECK: storePatchConstant.f32(i32 106, i32 2, i32 6, i8 0
+// CHECK: storePatchConstant.f32(i32 106, i32 2, i32 7, i8 0
+
+
+//--------------------------------------------------------------------------------------
+// SimpleTessellation.hlsl
+//
+// Advanced Technology Group (ATG)
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//--------------------------------------------------------------------------------------
+
+struct PSSceneIn
+{
+    float4 pos  : SV_Position;
+    float2 tex  : TEXCOORD0;
+    float3 norm : NORMAL;
+
+uint   RTIndex      : SV_RenderTargetArrayIndex;
+};
+
+
+//////////////////////////////////////////////////////////////////////////////////////////
+// Simple forwarding Tessellation shaders
+
+struct HSPerVertexData
+{
+    // This is just the original vertex verbatim. In many real life cases this would be a
+    // control point instead
+    PSSceneIn v;
+};
+
+struct HSPerPatchData
+{
+    // We at least have to specify tess factors per patch
+    // As we're tesselating triangles, there will be 4 tess factors
+    // In real life case this might contain face normal, for example
+	float	edges[ 3 ]	: SV_TessFactor;
+	float	inside		: SV_InsideTessFactor;
+        float   custom[8]       : CCC;
+};
+
+float4 HSPerPatchFunc()
+{
+    return 1.8;
+}
+
+int  count;
+float4 c[16];
+
+HSPerPatchData HSPerPatchFunc( const InputPatch< PSSceneIn, 3 > points )
+{
+    HSPerPatchData d;
+
+    d.edges[ 0 ] = 1;
+    d.edges[ 1 ] = 1;
+    d.edges[ 2 ] = 1;
+    d.inside = 1;
+    for (uint i=0;i<count;i++) {
+        d.custom[i] = c[i].x;
+    }    
+    return d;
+}
+
+// hull per-control point shader
+[domain("tri")]
+[partitioning("fractional_odd")]
+[outputtopology("triangle_cw")]
+[patchconstantfunc("HSPerPatchFunc")]
+[outputcontrolpoints(3)]
+HSPerVertexData main( const uint id : SV_OutputControlPointID,
+                               const InputPatch< PSSceneIn, 3 > points )
+{
+    HSPerVertexData v;
+
+    // Just forward the vertex
+    v.v = points[ id ];
+
+	return v;
+}
+
+

+ 26 - 0
tools/clang/test/HLSL/eliminate_dynamic_output6.hlsl

@@ -0,0 +1,26 @@
+// RUN: %dxc -Emain -Tvs_6_0 %s | %opt -S -hlsl-dxil-eliminate-output-dynamic | %FileCheck %s
+
+// CHECK-NOT: storeOutput.f32(i32 5, i32 0, i32 %i
+// CHECK-NOT: storeOutput.f32(i32 5, i32 0, i32 0, i8 0, float 0x3FF99999A0000000
+// CHECK: 0x3FF99999A0000000
+// CHECK: storeOutput.f32(i32 5, i32 0, i32 0
+// CHECK: storeOutput.f32(i32 5, i32 0, i32 1
+// CHECK: storeOutput.f32(i32 5, i32 0, i32 2
+// CHECK: storeOutput.f32(i32 5, i32 0, i32 3
+// CHECK: storeOutput.f32(i32 5, i32 0, i32 4
+// CHECK: storeOutput.f32(i32 5, i32 0, i32 5
+// CHECK: storeOutput.f32(i32 5, i32 0, i32 6
+// CHECK: storeOutput.f32(i32 5, i32 0, i32 7
+
+int  count;
+float4 c[16];
+
+float4 main(out float o[8] : I, float4 pos: POS) : SV_POSITION {
+
+    for (uint i=0;i<count;i++)
+        o[i] = c[i].x;
+    o[0] = 1.6;
+
+    return pos;
+}
+

+ 30 - 0
tools/clang/unittests/HLSL/CompilerTest.cpp

@@ -419,6 +419,12 @@ public:
   TEST_METHOD(CodeGenDot1)
   TEST_METHOD(CodeGenDynamic_Resources)
   TEST_METHOD(CodeGenEffectSkip)
+  TEST_METHOD(CodeGenEliminateDynamicIndexing)
+  TEST_METHOD(CodeGenEliminateDynamicIndexing2)
+  TEST_METHOD(CodeGenEliminateDynamicIndexing3)
+  TEST_METHOD(CodeGenEliminateDynamicIndexing4)
+  TEST_METHOD(CodeGenEliminateDynamicIndexing5)
+  TEST_METHOD(CodeGenEliminateDynamicIndexing6)
   TEST_METHOD(CodeGenEmpty)
   TEST_METHOD(CodeGenEmptyStruct)
   TEST_METHOD(CodeGenEarlyDepthStencil)
@@ -2414,6 +2420,30 @@ TEST_F(CompilerTest, CodeGenEffectSkip) {
   CodeGenTestCheck(L"..\\CodeGenHLSL\\effect_skip.hlsl");
 }
 
+TEST_F(CompilerTest, CodeGenEliminateDynamicIndexing) {
+  CodeGenTestCheck(L"eliminate_dynamic_output.hlsl");
+}
+
+TEST_F(CompilerTest, CodeGenEliminateDynamicIndexing2) {
+  CodeGenTestCheck(L"eliminate_dynamic_output2.hlsl");
+}
+
+TEST_F(CompilerTest, CodeGenEliminateDynamicIndexing3) {
+  CodeGenTestCheck(L"eliminate_dynamic_output3.hlsl");
+}
+
+TEST_F(CompilerTest, CodeGenEliminateDynamicIndexing4) {
+  CodeGenTestCheck(L"eliminate_dynamic_output4.hlsl");
+}
+
+TEST_F(CompilerTest, CodeGenEliminateDynamicIndexing5) {
+  CodeGenTestCheck(L"eliminate_dynamic_output5.hlsl");
+}
+
+TEST_F(CompilerTest, CodeGenEliminateDynamicIndexing6) {
+  CodeGenTestCheck(L"eliminate_dynamic_output6.hlsl");
+}
+
 TEST_F(CompilerTest, CodeGenEmpty) {
   CodeGenTest(L"..\\CodeGenHLSL\\empty.hlsl");
 }

+ 1 - 0
utils/hct/hctdb.py

@@ -1262,6 +1262,7 @@ class db_dxil(object):
         add_pass('multi-dim-one-dim', 'MultiDimArrayToOneDimArray', 'Flatten multi-dim array into one-dim array', [])
         add_pass('resource-handle', 'ResourceToHandle', 'Lower resource into handle', [])
         add_pass('hlsl-dxil-condense', 'DxilCondenseResources', 'DXIL Condense Resources', [])
+        add_pass('hlsl-dxil-eliminate-output-dynamic', 'DxilEliminateOutputDynamicIndexing', 'DXIL eliminate ouptut dynamic indexing', [])
         add_pass('hlsl-dxilemit', 'DxilEmitMetadata', 'HLSL DXIL Metadata Emit', [])
         add_pass('hlsl-dxilload', 'DxilLoadMetadata', 'HLSL DXIL Metadata Load', [])
         add_pass('hlsl-hca', 'HoistConstantArray', 'HLSL constant array hoisting', [])