浏览代码

Allow optimizations to eliminate phis on undef resources before considering them errors

Some large shaders exhibit a behavior where phi nodes are created for resources, in which one of the possible incoming values is undef. This gets cleaned up later such that there are no undef resources left. However the fail-undef-resources pass has already failed compilation by that point. The fix is to change that pass to invalidate-undef-resources and replace the undefs with a special invalid value, such that we can produce an error later if still necessary, when optimization passes have been run such that temporary undef resources have been eliminated.
Tristan Labelle 6 年之前
父节点
当前提交
3527762fd0

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

@@ -67,7 +67,7 @@ ModulePass *createDxilLegalizeResources();
 ModulePass *createDxilLegalizeEvalOperationsPass();
 ModulePass *createDxilLegalizeEvalOperationsPass();
 FunctionPass *createDxilLegalizeSampleOffsetPass();
 FunctionPass *createDxilLegalizeSampleOffsetPass();
 FunctionPass *createDxilSimpleGVNHoistPass();
 FunctionPass *createDxilSimpleGVNHoistPass();
-ModulePass *createFailUndefResourcePass();
+ModulePass *createInvalidateUndefResourcesPass();
 FunctionPass *createSimplifyInstPass();
 FunctionPass *createSimplifyInstPass();
 ModulePass *createDxilTranslateRawBuffer();
 ModulePass *createDxilTranslateRawBuffer();
 ModulePass *createNoPausePassesPass();
 ModulePass *createNoPausePassesPass();
@@ -99,7 +99,7 @@ void initializeDxilLegalizeResourcesPass(llvm::PassRegistry&);
 void initializeDxilLegalizeEvalOperationsPass(llvm::PassRegistry&);
 void initializeDxilLegalizeEvalOperationsPass(llvm::PassRegistry&);
 void initializeDxilLegalizeSampleOffsetPassPass(llvm::PassRegistry&);
 void initializeDxilLegalizeSampleOffsetPassPass(llvm::PassRegistry&);
 void initializeDxilSimpleGVNHoistPass(llvm::PassRegistry&);
 void initializeDxilSimpleGVNHoistPass(llvm::PassRegistry&);
-void initializeFailUndefResourcePass(llvm::PassRegistry&);
+void initializeInvalidateUndefResourcesPass(llvm::PassRegistry&);
 void initializeSimplifyInstPass(llvm::PassRegistry&);
 void initializeSimplifyInstPass(llvm::PassRegistry&);
 void initializeDxilTranslateRawBufferPass(llvm::PassRegistry&);
 void initializeDxilTranslateRawBufferPass(llvm::PassRegistry&);
 void initializeNoPausePassesPass(llvm::PassRegistry&);
 void initializeNoPausePassesPass(llvm::PassRegistry&);

+ 1 - 1
lib/HLSL/DxcOptimizer.cpp

@@ -110,7 +110,7 @@ HRESULT SetupRegistryPassForHLSL() {
     initializeDynamicIndexingVectorToArrayPass(Registry);
     initializeDynamicIndexingVectorToArrayPass(Registry);
     initializeEarlyCSELegacyPassPass(Registry);
     initializeEarlyCSELegacyPassPass(Registry);
     initializeEliminateAvailableExternallyPass(Registry);
     initializeEliminateAvailableExternallyPass(Registry);
-    initializeFailUndefResourcePass(Registry);
+    initializeInvalidateUndefResourcesPass(Registry);
     initializeFloat2IntPass(Registry);
     initializeFloat2IntPass(Registry);
     initializeFunctionAttrsPass(Registry);
     initializeFunctionAttrsPass(Registry);
     initializeGVNPass(Registry);
     initializeGVNPass(Registry);

+ 20 - 0
lib/HLSL/DxilCondenseResources.cpp

@@ -447,6 +447,8 @@ public:
     m_bIsLib = DM.GetShaderModel()->IsLib();
     m_bIsLib = DM.GetShaderModel()->IsLib();
     m_bLegalizationFailed = false;
     m_bLegalizationFailed = false;
 
 
+    FailOnPoisonResources();
+
     bool bChanged = false;
     bool bChanged = false;
     unsigned numResources = DM.GetCBuffers().size() + DM.GetUAVs().size() +
     unsigned numResources = DM.GetCBuffers().size() + DM.GetUAVs().size() +
                             DM.GetSRVs().size() + DM.GetSamplers().size();
                             DM.GetSRVs().size() + DM.GetSamplers().size();
@@ -506,6 +508,7 @@ public:
   }
   }
 
 
 private:
 private:
+  void FailOnPoisonResources();
   bool RemovePhiOnResource();
   bool RemovePhiOnResource();
   void UpdateResourceSymbols();
   void UpdateResourceSymbols();
   void TranslateDxilResourceUses(DxilResourceBase &res);
   void TranslateDxilResourceUses(DxilResourceBase &res);
@@ -1694,6 +1697,23 @@ void UpdateStructTypeForLegacyLayoutOnDM(DxilModule &DM) {
 
 
 } // namespace
 } // namespace
 
 
+void DxilLowerCreateHandleForLib::FailOnPoisonResources() {
+  // A previous pass replaced all undef resources with constant zero resources.
+  // If those made it here, the program is malformed.
+  for (Function &Func : this->m_DM->GetModule()->functions()) {
+    hlsl::OP::OpCodeClass OpcodeClass;
+    if (m_DM->GetOP()->GetOpCodeClass(&Func, OpcodeClass)
+      && OpcodeClass == OP::OpCodeClass::CreateHandleForLib) {
+      Type *ResTy = Func.getFunctionType()->getParamType(
+        DXIL::OperandIndex::kCreateHandleForLibResOpIdx);
+      Constant *PoisonRes = ConstantAggregateZero::get(ResTy);
+      for (User *PoisonUser : PoisonRes->users())
+        if (Instruction *PoisonUserInst = dyn_cast<Instruction>(PoisonUser))
+          dxilutil::EmitResMappingError(PoisonUserInst);
+    }
+  }
+}
+
 void DxilLowerCreateHandleForLib::UpdateStructTypeForLegacyLayout() {
 void DxilLowerCreateHandleForLib::UpdateStructTypeForLegacyLayout() {
   UpdateStructTypeForLegacyLayoutOnDM(*m_DM);
   UpdateStructTypeForLegacyLayoutOnDM(*m_DM);
 }
 }

+ 19 - 15
lib/HLSL/DxilPreparePasses.cpp

@@ -36,40 +36,44 @@ using namespace llvm;
 using namespace hlsl;
 using namespace hlsl;
 
 
 namespace {
 namespace {
-class FailUndefResource : public ModulePass {
+class InvalidateUndefResources : public ModulePass {
 public:
 public:
   static char ID;
   static char ID;
 
 
-  explicit FailUndefResource() : ModulePass(ID) {
+  explicit InvalidateUndefResources() : ModulePass(ID) {
     initializeScalarizerPass(*PassRegistry::getPassRegistry());
     initializeScalarizerPass(*PassRegistry::getPassRegistry());
   }
   }
 
 
-  const char *getPassName() const override { return "Fail on undef resource use"; }
+  const char *getPassName() const override { return "Invalidate undef resources"; }
 
 
   bool runOnModule(Module &M) override;
   bool runOnModule(Module &M) override;
 };
 };
 }
 }
 
 
-char FailUndefResource::ID = 0;
+char InvalidateUndefResources::ID = 0;
 
 
-ModulePass *llvm::createFailUndefResourcePass() { return new FailUndefResource(); }
+ModulePass *llvm::createInvalidateUndefResourcesPass() { return new InvalidateUndefResources(); }
 
 
-INITIALIZE_PASS(FailUndefResource, "fail-undef-resource", "Fail on undef resource use", false, false)
+INITIALIZE_PASS(InvalidateUndefResources, "invalidate-undef-resource", "Invalidate undef resources", false, false)
 
 
-bool FailUndefResource::runOnModule(Module &M) {
-  // Undef resources may be removed on simplify due to the interpretation
-  // of undef that any value could be substituted for identical meaning.
-  // However, these likely indicate uninitialized locals being used in
-  // some code path, which we should catch and report.
+bool InvalidateUndefResources::runOnModule(Module &M) {
+  // Undef resources typically indicate uninitialized locals being used
+  // in some code path, which we should catch and report. However, some
+  // code patterns in large shaders cause dead undef resources to momentarily,
+  // which is not an error. We must wait until cleanup passes
+  // have run to know whether we must produce an error.
+  // However, we can't leave the undef values in because they could eliminated,
+  // such as by reading from resources seen in a code path that was not taken.
+  // We avoid the problem by replacing undef values by another invalid
+  // value that we can identify later.
   for (auto &F : M.functions()) {
   for (auto &F : M.functions()) {
     if (GetHLOpcodeGroupByName(&F) == HLOpcodeGroup::HLCreateHandle) {
     if (GetHLOpcodeGroupByName(&F) == HLOpcodeGroup::HLCreateHandle) {
       Type *ResTy = F.getFunctionType()->getParamType(
       Type *ResTy = F.getFunctionType()->getParamType(
         HLOperandIndex::kCreateHandleResourceOpIdx);
         HLOperandIndex::kCreateHandleResourceOpIdx);
       UndefValue *UndefRes = UndefValue::get(ResTy);
       UndefValue *UndefRes = UndefValue::get(ResTy);
-      for (auto U : UndefRes->users()) {
-        // Only report instruction users.
-        if (Instruction *I = dyn_cast<Instruction>(U))
-          dxilutil::EmitResMappingError(I);
+      if (!UndefRes->use_empty()) {
+        Constant *InvalidRes = ConstantAggregateZero::get(ResTy);
+        UndefRes->replaceAllUsesWith(InvalidRes);
       }
       }
     }
     }
   }
   }

+ 1 - 1
lib/Transforms/IPO/PassManagerBuilder.cpp

@@ -277,7 +277,7 @@ static void addHLSLPasses(bool HLSLHighLevel, unsigned OptLevel, hlsl::HLSLExten
   MPM.add(createDxilPromoteLocalResources());
   MPM.add(createDxilPromoteLocalResources());
   MPM.add(createDxilPromoteStaticResources());
   MPM.add(createDxilPromoteStaticResources());
   // Verify no undef resource again after promotion
   // Verify no undef resource again after promotion
-  MPM.add(createFailUndefResourcePass());
+  MPM.add(createInvalidateUndefResourcesPass());
 
 
   MPM.add(createDxilGenerationPass(NoOpt, ExtHelper));
   MPM.add(createDxilGenerationPass(NoOpt, ExtHelper));
 
 

+ 1 - 1
utils/hct/hctdb.py

@@ -1560,7 +1560,7 @@ class db_dxil(object):
         add_pass('hlsl-dxil-legalize-eval-operations', 'DxilLegalizeEvalOperations', 'DXIL legalize eval operations', [])
         add_pass('hlsl-dxil-legalize-eval-operations', 'DxilLegalizeEvalOperations', 'DXIL legalize eval operations', [])
         add_pass('dxilgen', 'DxilGenerationPass', 'HLSL DXIL Generation', [
         add_pass('dxilgen', 'DxilGenerationPass', 'HLSL DXIL Generation', [
             {'n':'NotOptimized','t':'bool','c':1}])
             {'n':'NotOptimized','t':'bool','c':1}])
-        add_pass('fail-undef-resource', 'FailUndefResource', 'Fail on undef resource use', [])
+        add_pass('invalidate-undef-resource', 'InvalidateUndefResources', 'Invalidate undef resources', [])
         add_pass('simplify-inst', 'SimplifyInst', 'Simplify Instructions', [])
         add_pass('simplify-inst', 'SimplifyInst', 'Simplify Instructions', [])
         add_pass('hlsl-dxil-precise', 'DxilPrecisePropagatePass', 'DXIL precise attribute propagate', [])
         add_pass('hlsl-dxil-precise', 'DxilPrecisePropagatePass', 'DXIL precise attribute propagate', [])
         add_pass('dxil-legalize-sample-offset', 'DxilLegalizeSampleOffsetPass', 'DXIL legalize sample offset', [])
         add_pass('dxil-legalize-sample-offset', 'DxilLegalizeSampleOffsetPass', 'DXIL legalize sample offset', [])