Browse Source

Separated dead block removal to its own pass. Fixed bug where dead resources are not removed (#2744)

Adam Yang 5 years ago
parent
commit
a98faf6a98

+ 1 - 0
include/llvm/InitializePasses.h

@@ -269,6 +269,7 @@ void initializeDxilFixConstArrayInitializerPass(PassRegistry&);
 void initializeDxilInsertPreservesPass(PassRegistry&);
 void initializeDxilFinalizePreservesPass(PassRegistry&);
 void initializeDxilPreserveToSelectPass(PassRegistry&);
+void initializeDxilRemoveDeadBlocksPass(PassRegistry&);
 // HLSL Change Ends
 void initializeScalarEvolutionAliasAnalysisPass(PassRegistry&);
 void initializeScalarEvolutionPass(PassRegistry&);

+ 3 - 0
include/llvm/Transforms/Scalar.h

@@ -155,6 +155,9 @@ void initializeDxilFinalizePreservesPass(PassRegistry&);
 Pass *createDxilPreserveToSelectPass();
 void initializeDxilPreserveToSelectPass(PassRegistry&);
 
+Pass *createDxilRemoveDeadBlocksPass();
+void initializeDxilRemoveDeadBlocksPass(PassRegistry&);
+
 //===----------------------------------------------------------------------===//
 //
 // LowerStaticGlobalIntoAlloca. Replace static globals with alloca if only used

+ 6 - 0
lib/Analysis/DxilValueCache.cpp

@@ -216,6 +216,12 @@ Value *DxilValueCache::SimplifyAndCacheResult(Instruction *I, DominatorTree *DT)
   else if (Instruction::Load == I->getOpcode()) {
     Simplified = ProcessAndSimpilfy_Load(I, DT);
   }
+  else if (Instruction::GetElementPtr == I->getOpcode()) {
+    SmallVector<Value *, 4> Ops;
+    for (unsigned i = 0; i < I->getNumOperands(); i++)
+      Ops.push_back(TryGetCachedValue(I->getOperand(i)));
+    Simplified = llvm::SimplifyGEPInst(Ops, DL, nullptr, DT);
+  }
   // The rest of the checks use LLVM stock simplifications
   else if (I->isBinaryOp()) {
     Simplified =

+ 1 - 0
lib/HLSL/DxcOptimizer.cpp

@@ -112,6 +112,7 @@ HRESULT SetupRegistryPassForHLSL() {
     initializeDxilPreserveToSelectPass(Registry);
     initializeDxilPromoteLocalResourcesPass(Registry);
     initializeDxilPromoteStaticResourcesPass(Registry);
+    initializeDxilRemoveDeadBlocksPass(Registry);
     initializeDxilSimpleGVNHoistPass(Registry);
     initializeDxilTranslateRawBufferPass(Registry);
     initializeDxilValidateWaveSensitivityPass(Registry);

+ 11 - 127
lib/HLSL/DxilCondenseResources.cpp

@@ -424,126 +424,6 @@ ModulePass *llvm::createDxilCondenseResourcesPass() {
 
 INITIALIZE_PASS(DxilCondenseResources, "hlsl-dxil-condense", "DXIL Condense Resources", false, false)
 
-static
-bool EraseDeadBlocks(Module &M, DxilValueCache *DVC) {
-  std::unordered_set<BasicBlock *> Seen;
-  std::vector<BasicBlock *> WorkList;
-
-  bool Changed = false;
-
-  for (Function &F : M) {
-    if (F.isDeclaration())
-      continue;
-    Seen.clear();
-    WorkList.clear();
-
-    auto Add = [&WorkList, &Seen](BasicBlock *BB) {
-      if (!Seen.count(BB)) {
-        WorkList.push_back(BB);
-        Seen.insert(BB);
-      }
-    };
-
-    Add(&F.getEntryBlock());
-
-    // Go through blocks
-    while (WorkList.size()) {
-      BasicBlock *BB = WorkList.back();
-      WorkList.pop_back();
-
-      if (BranchInst *Br = dyn_cast<BranchInst>(BB->getTerminator())) {
-        if (Br->isUnconditional()) {
-          BasicBlock *Succ = Br->getSuccessor(0);
-          Add(Succ);
-        }
-        else {
-          bool IsConstant = false;
-          if (Value *V = DVC->GetValue(Br->getCondition())) {
-            if (ConstantInt *C = dyn_cast<ConstantInt>(V)) {
-              bool IsTrue = C->getLimitedValue() != 0;
-              BasicBlock *Succ = IsTrue ?
-                Br->getSuccessor(0) : Br->getSuccessor(1);
-              Add(Succ);
-              IsConstant = true;
-            }
-          }
-          if (!IsConstant) {
-            Add(Br->getSuccessor(0));
-            Add(Br->getSuccessor(1));
-          }
-        }
-      }
-      else if (SwitchInst *Switch = dyn_cast<SwitchInst>(BB->getTerminator())) {
-        for (unsigned i = 0; i < Switch->getNumSuccessors(); i++) {
-          Add(Switch->getSuccessor(i));
-        }
-      }
-    }
-
-    if (Seen.size() == F.size())
-      continue;
-
-    Changed = true;
-
-    std::vector<BasicBlock *> DeadBlocks;
-
-    // Reconnect edges and everything
-    for (auto it = F.begin(); it != F.end();) {
-      BasicBlock *BB = &*(it++);
-      if (Seen.count(BB))
-        continue;
-
-      DeadBlocks.push_back(BB);
-
-      // Make predecessors branch somewhere else and fix the phi nodes
-      for (auto pred_it = pred_begin(BB); pred_it != pred_end(BB);) {
-        BasicBlock *PredBB = *(pred_it++);
-        if (!Seen.count(PredBB))
-          continue;
-        TerminatorInst *TI = PredBB->getTerminator();
-        if (!TI) continue;
-        BranchInst *Br = dyn_cast<BranchInst>(TI);
-        if (!Br || Br->isUnconditional()) continue;
-
-        BasicBlock *Other = Br->getSuccessor(0) == BB ?
-          Br->getSuccessor(1) : Br->getSuccessor(0);
-
-        BranchInst *NewBr = BranchInst::Create(Other, Br);
-        hlsl::DxilMDHelper::CopyMetadata(*NewBr, *Br);
-        Br->eraseFromParent();
-      }
-
-      // Fix phi nodes in successors
-      for (auto succ_it = succ_begin(BB); succ_it != succ_end(BB); succ_it++) {
-        BasicBlock *SuccBB = *succ_it;
-        if (!Seen.count(SuccBB)) continue;
-        for (auto inst_it = SuccBB->begin(); inst_it != SuccBB->end();) {
-          Instruction *I = &*(inst_it++);
-          if (PHINode *PN = dyn_cast<PHINode>(I))
-            PN->removeIncomingValue(BB, true);
-          else
-            break;
-        }
-      }
-
-      // Erase all instructions in block
-      while (BB->size()) {
-        Instruction *I = &BB->back();
-        if (!I->getType()->isVoidTy())
-          I->replaceAllUsesWith(UndefValue::get(I->getType()));
-        I->eraseFromParent();
-      }
-    }
-
-    for (BasicBlock *BB : DeadBlocks) {
-      BB->eraseFromParent();
-    }
-
-  }
-
-  return Changed;
-}
-
 static
 bool LegalizeResourcesPHIs(Module &M, DxilValueCache *DVC) {
   // Simple pass to collect resource PHI's
@@ -564,9 +444,6 @@ bool LegalizeResourcesPHIs(Module &M, DxilValueCache *DVC) {
     }
   }
 
-  if (PHIs.empty())
-    return false;
-
   bool Changed = false;
 
   SmallVector<Instruction *, 8> DCEWorklist;
@@ -625,6 +502,7 @@ bool LegalizeResourcesPHIs(Module &M, DxilValueCache *DVC) {
       // Remove the instruction from the worklist if it still exists in it.
       DCEWorklist.erase(std::remove(DCEWorklist.begin(), DCEWorklist.end(), I),
                      DCEWorklist.end());
+      Changed = true;
     }
   }
 
@@ -688,6 +566,16 @@ public:
     if (0 == newResources)
       return bChanged;
 
+    {
+      DxilValueCache *DVC = &getAnalysis<DxilValueCache>();
+      bool bLocalChanged = LegalizeResourcesPHIs(M, DVC);
+      if (bLocalChanged) {
+        // Remove unused resources.
+        DM.RemoveResourcesWithUnusedSymbols();
+      }
+      bChanged |= bLocalChanged;
+    }
+
     bChanged |= ResourceRegisterAllocator.AllocateRegisters(DM);
 
     // Fill in top-level CBuffer variable usage bit
@@ -696,10 +584,6 @@ public:
     if (m_bIsLib && DM.GetShaderModel()->GetMinor() == ShaderModel::kOfflineMinor)
       return bChanged;
 
-    DxilValueCache *DVC = &getAnalysis<DxilValueCache>();
-    bChanged |= EraseDeadBlocks(M, DVC);
-    bChanged |= LegalizeResourcesPHIs(M, DVC);
-
     // Make sure no select on resource.
     bChanged |= RemovePhiOnResource();
 

+ 2 - 0
lib/Transforms/IPO/PassManagerBuilder.cpp

@@ -352,6 +352,7 @@ void PassManagerBuilder::populateModulePassManager(
     if (!HLSLHighLevel) {
       MPM.add(createDxilConvergentClearPass());
       MPM.add(createMultiDimArrayToOneDimArrayPass());
+      MPM.add(createDxilRemoveDeadBlocksPass());
       MPM.add(createDxilLowerCreateHandleForLibPass());
       MPM.add(createDxilTranslateRawBuffer());
       MPM.add(createDxilLegalizeSampleOffsetPass());
@@ -640,6 +641,7 @@ void PassManagerBuilder::populateModulePassManager(
                                               // so no unused resources get re-added to
                                               // DxilModule.
     MPM.add(createMultiDimArrayToOneDimArrayPass());
+    MPM.add(createDxilRemoveDeadBlocksPass());
     MPM.add(createDxilLowerCreateHandleForLibPass());
     MPM.add(createDxilTranslateRawBuffer());
     MPM.add(createDeadCodeEliminationPass());

+ 1 - 0
lib/Transforms/Scalar/CMakeLists.txt

@@ -46,6 +46,7 @@ add_llvm_library(LLVMScalarOpts
   ScalarReplAggregates.cpp
   ScalarReplAggregatesHLSL.cpp  # HLSL Change
   DxilLoopUnroll.cpp # HLSL Change
+  DxilRemoveDeadBlocks.cpp # HLSL Change
   DxilEraseDeadRegion.cpp # HLSL Change
   DxilFixConstArrayInitializer.cpp # HLSL Change
   DxilEliminateVector.cpp # HLSL Change

+ 160 - 0
lib/Transforms/Scalar/DxilRemoveDeadBlocks.cpp

@@ -0,0 +1,160 @@
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// DxilRemoveDeadBlocks.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.                                     //
+//                                                                           //
+// Pass to use value tracker to remove dead blocks.                          //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+#include "llvm/Pass.h"
+#include "llvm/IR/Function.h"
+#include "llvm/IR/Instruction.h"
+#include "llvm/IR/Instructions.h"
+#include "llvm/IR/Constants.h"
+#include "llvm/IR/CFG.h"
+#include "llvm/Transforms/Scalar.h"
+#include "llvm/Analysis/DxilValueCache.h"
+
+#include "dxc/DXIL/DxilMetadataHelper.h"
+
+#include <unordered_set>
+
+using namespace llvm;
+
+static bool EraseDeadBlocks(Function &F, DxilValueCache *DVC) {
+  std::unordered_set<BasicBlock *> Seen;
+  std::vector<BasicBlock *> WorkList;
+
+  auto Add = [&WorkList, &Seen](BasicBlock *BB) {
+    if (!Seen.count(BB)) {
+      WorkList.push_back(BB);
+      Seen.insert(BB);
+    }
+  };
+
+  Add(&F.getEntryBlock());
+
+  // Go through blocks
+  while (WorkList.size()) {
+    BasicBlock *BB = WorkList.back();
+    WorkList.pop_back();
+
+    if (BranchInst *Br = dyn_cast<BranchInst>(BB->getTerminator())) {
+      if (Br->isUnconditional()) {
+        BasicBlock *Succ = Br->getSuccessor(0);
+        Add(Succ);
+      }
+      else {
+        bool IsConstant = false;
+        if (Value *V = DVC->GetValue(Br->getCondition())) {
+          if (ConstantInt *C = dyn_cast<ConstantInt>(V)) {
+            bool IsTrue = C->getLimitedValue() != 0;
+            BasicBlock *Succ = IsTrue ?
+              Br->getSuccessor(0) : Br->getSuccessor(1);
+            Add(Succ);
+            IsConstant = true;
+          }
+        }
+        if (!IsConstant) {
+          Add(Br->getSuccessor(0));
+          Add(Br->getSuccessor(1));
+        }
+      }
+    }
+    else if (SwitchInst *Switch = dyn_cast<SwitchInst>(BB->getTerminator())) {
+      for (unsigned i = 0; i < Switch->getNumSuccessors(); i++) {
+        Add(Switch->getSuccessor(i));
+      }
+    }
+  }
+
+  if (Seen.size() == F.size())
+    return false;
+
+  std::vector<BasicBlock *> DeadBlocks;
+
+  // Reconnect edges and everything
+  for (auto it = F.begin(); it != F.end();) {
+    BasicBlock *BB = &*(it++);
+    if (Seen.count(BB))
+      continue;
+
+    DeadBlocks.push_back(BB);
+
+    // Make predecessors branch somewhere else and fix the phi nodes
+    for (auto pred_it = pred_begin(BB); pred_it != pred_end(BB);) {
+      BasicBlock *PredBB = *(pred_it++);
+      if (!Seen.count(PredBB))
+        continue;
+      TerminatorInst *TI = PredBB->getTerminator();
+      if (!TI) continue;
+      BranchInst *Br = dyn_cast<BranchInst>(TI);
+      if (!Br || Br->isUnconditional()) continue;
+
+      BasicBlock *Other = Br->getSuccessor(0) == BB ?
+        Br->getSuccessor(1) : Br->getSuccessor(0);
+
+      BranchInst *NewBr = BranchInst::Create(Other, Br);
+      hlsl::DxilMDHelper::CopyMetadata(*NewBr, *Br);
+      Br->eraseFromParent();
+    }
+
+    // Fix phi nodes in successors
+    for (auto succ_it = succ_begin(BB); succ_it != succ_end(BB); succ_it++) {
+      BasicBlock *SuccBB = *succ_it;
+      if (!Seen.count(SuccBB)) continue;
+      for (auto inst_it = SuccBB->begin(); inst_it != SuccBB->end();) {
+        Instruction *I = &*(inst_it++);
+        if (PHINode *PN = dyn_cast<PHINode>(I))
+          PN->removeIncomingValue(BB, true);
+        else
+          break;
+      }
+    }
+
+    // Erase all instructions in block
+    while (BB->size()) {
+      Instruction *I = &BB->back();
+      if (!I->getType()->isVoidTy())
+        I->replaceAllUsesWith(UndefValue::get(I->getType()));
+      I->eraseFromParent();
+    }
+  }
+
+  for (BasicBlock *BB : DeadBlocks) {
+    BB->eraseFromParent();
+  }
+
+  return true;
+}
+
+namespace {
+
+struct DxilRemoveDeadBlocks : public FunctionPass {
+  static char ID;
+  DxilRemoveDeadBlocks() : FunctionPass(ID) {
+    initializeDxilRemoveDeadBlocksPass(*PassRegistry::getPassRegistry());
+  }
+  void getAnalysisUsage(AnalysisUsage &AU) const override {
+    AU.addRequired<DxilValueCache>();
+  }
+  bool runOnFunction(Function &F) override {
+    DxilValueCache *DVC = &getAnalysis<DxilValueCache>();
+    return EraseDeadBlocks(F, DVC);
+  }
+};
+
+}
+
+char DxilRemoveDeadBlocks::ID;
+
+Pass *llvm::createDxilRemoveDeadBlocksPass() {
+  return new DxilRemoveDeadBlocks();
+}
+
+INITIALIZE_PASS_BEGIN(DxilRemoveDeadBlocks, "dxil-remove-dead-blocks", "DXIL Remove Dead Blocks", false, false)
+INITIALIZE_PASS_DEPENDENCY(DxilValueCache)
+INITIALIZE_PASS_END(DxilRemoveDeadBlocks, "dxil-remove-dead-blocks", "DXIL Remove Dead Blocks", false, false)

+ 1 - 1
tools/clang/test/HLSLFileCheck/dxil/debug/value_cache/cfg.hlsl

@@ -24,7 +24,7 @@ Texture2D h(bool foo3) {
 [RootSignature("DescriptorTable(SRV(t0, numDescriptors=3), SRV(t42))")]
 float4 main() : sv_target {
 
-  // CHECK: %[[handle:.+]] = call %dx.types.Handle @dx.op.createHandle(i32 57, i8 0, i32 1, i32 42
+  // CHECK: %[[handle:.+]] = call %dx.types.Handle @dx.op.createHandle(i32 57, i8 0, i32 0, i32 42
 
   gG = true;
   gG2 = false;

+ 1 - 1
tools/clang/test/HLSLFileCheck/dxil/debug/value_cache/cfg2.hlsl

@@ -35,7 +35,7 @@ Texture2D h(bool foo3) {
 
 [RootSignature("DescriptorTable(SRV(t0, numDescriptors=4), SRV(t42))")]
 float4 main() : sv_target {
-  // CHECK: %[[handle:.+]] = call %dx.types.Handle @dx.op.createHandle(i32 57, i8 0, i32 1, i32 42
+  // CHECK: %[[handle:.+]] = call %dx.types.Handle @dx.op.createHandle(i32 57, i8 0, i32 0, i32 42
 
   gG = true;
   gG2 = false;

+ 1 - 1
tools/clang/test/HLSLFileCheck/dxil/debug/value_cache/load.hlsl

@@ -12,7 +12,7 @@ const static float2 my_offsets[] = {
 
 [RootSignature("DescriptorTable(SRV(t0), SRV(t42)), DescriptorTable(Sampler(s0))")]
 float4 main(uint2 uv : TEXCOORD) : SV_Target {
-  // CHECK: %[[handle:.+]] = call %dx.types.Handle @dx.op.createHandle(i32 57, i8 0, i32 1, i32 42
+  // CHECK: %[[handle:.+]] = call %dx.types.Handle @dx.op.createHandle(i32 57, i8 0, i32 0, i32 42
   int x = 0;
   int y = 0;
 

+ 1 - 1
tools/clang/test/HLSLFileCheck/dxil/debug/value_cache/resource_array.hlsl

@@ -12,7 +12,7 @@ const static float2 my_offsets[] = {
 
 [RootSignature("DescriptorTable(SRV(t0, numDescriptors=42), SRV(t42)), DescriptorTable(Sampler(s0))")]
 float4 main(uint2 uv : TEXCOORD, uint a : A) : SV_Target {
-  // CHECK: %[[handle:.+]] = call %dx.types.Handle @dx.op.createHandle(i32 57, i8 0, i32 1, i32 42
+  // CHECK: %[[handle:.+]] = call %dx.types.Handle @dx.op.createHandle(i32 57, i8 0, i32 0, i32 42
   int x = 0;
   int y = 0;
 

+ 1 - 1
tools/clang/test/HLSLFileCheck/dxil/debug/value_cache/resource_array2.hlsl

@@ -42,7 +42,7 @@ Texture2D h(bool foo3) {
 
 [RootSignature("CBV(b0), DescriptorTable(SRV(t0, numDescriptors=42), SRV(t42), SRV(t43, numDescriptors=4))")]
 float4 main() : sv_target {
-  // CHECK: %[[handle:.+]] = call %dx.types.Handle @dx.op.createHandle(i32 57, i8 0, i32 1, i32 42
+  // CHECK: %[[handle:.+]] = call %dx.types.Handle @dx.op.createHandle(i32 57, i8 0, i32 0, i32 42
 
   local_tex1 = tex0[idx1];
   local_tex2 = tex0[idx2];

+ 1 - 1
tools/clang/test/HLSLFileCheck/dxil/debug/value_cache/right_branch.hlsl

@@ -7,7 +7,7 @@ Texture2D tex1 : register(t42);
 
 [RootSignature("DescriptorTable(SRV(t0), SRV(t42))")]
 float4 main() : SV_Target {
-  // CHECK: %[[handle:.+]] = call %dx.types.Handle @dx.op.createHandle(i32 57, i8 0, i32 1, i32 42
+  // CHECK: %[[handle:.+]] = call %dx.types.Handle @dx.op.createHandle(i32 57, i8 0, i32 0, i32 42
 
   float x = 10;
   float y = x + 5;

+ 41 - 0
tools/clang/test/HLSLFileCheck/passes/dxil/dxil_remove_dead_pass/deadblocks.hlsl

@@ -0,0 +1,41 @@
+// RUN: %dxc %s -T ps_6_0 -Od | FileCheck %s
+
+// Test that one of the textures have been removed completely since they have
+// the same register.
+
+// CHECK: @main
+
+SamplerState samp : register(s0);
+Texture2D tex0 : register(t0);
+Texture2D tex1 : register(t0); // Same register as tex1
+
+cbuffer cb : register ( b0 ) {
+  int2 g_count;
+  int g_delta;
+}
+
+float foo(bool flag) {
+  float result = 0;
+  [loop]
+  for (int y = 0; y < g_count.x; y += g_delta) {
+    [loop]
+    for (int x = 0; x < g_count.x; x += g_delta) {
+      float2 uv = float2(int2 (x,y));
+      float4 g;
+      if (flag) {
+        g = tex1.Gather(samp, uv, 1);
+      }
+      else {
+        g = tex0.Gather(samp, uv, 1);
+      }
+      result = g.x;
+    }
+  }
+  return result;
+}
+
+[RootSignature("CBV(b0),DescriptorTable(SRV(t0),SRV(t1)),DescriptorTable(Sampler(s0))")]
+float main() : SV_Target {
+  return foo(false);
+}
+

+ 1 - 0
utils/hct/hctdb.py

@@ -2047,6 +2047,7 @@ class db_dxil(object):
         add_pass('loop-idiom', 'LoopIdiomRecognize', "Recognize loop idioms", [])
         add_pass('dxil-loop-unroll', 'DxilLoopUnroll', 'DxilLoopUnroll', [])
         add_pass('dxil-erase-dead-region', 'DxilEraseDeadRegion', 'DxilEraseDeadRegion', [])
+        add_pass('dxil-remove-dead-blocks', 'DxilRemoveDeadBlocks', 'DxilRemoveDeadBlocks', [])
         add_pass('loop-deletion', 'LoopDeletion', "Delete dead loops", [])
         add_pass('loop-interchange', 'LoopInterchange', 'Interchanges loops for cache reuse', [])
         add_pass('loop-unroll', 'LoopUnroll', 'Unroll loops', [