Add id to name map
authorSteven Perron <stevenperron@google.com>
Tue, 13 Feb 2018 04:28:38 +0000 (23:28 -0500)
committerSteven Perron <stevenperron@google.com>
Wed, 14 Feb 2018 20:53:13 +0000 (15:53 -0500)
Adding a map from an id to it set of OpName and OpMemberName
instructions.  This will be used in KillNameAndDecorates to kill the
names for the ids that are being removed.

In my test, the compile time for 50 shaders went from 1m57s to 55s.
This was on linux using the release build.

Fixes #1290.

source/opt/if_conversion.h
source/opt/ir_context.cpp
source/opt/ir_context.h
source/opt/local_redundancy_elimination.h
source/opt/private_to_local_pass.h
source/opt/scalar_replacement_pass.h

index e70011b..eb97406 100644 (file)
@@ -33,7 +33,7 @@ class IfConversion : public Pass {
     return ir::IRContext::kAnalysisDefUse |
            ir::IRContext::kAnalysisDominatorAnalysis |
            ir::IRContext::kAnalysisInstrToBlockMapping |
-           ir::IRContext::kAnalysisCFG;
+           ir::IRContext::kAnalysisCFG | ir::IRContext::kAnalysisNameMap;
   }
 
  private:
index ce6ac0b..895c8a9 100644 (file)
@@ -42,6 +42,9 @@ void IRContext::BuildInvalidAnalyses(IRContext::Analysis set) {
   if (set & kAnalysisLoopAnalysis) {
     ResetLoopAnalysis();
   }
+  if (set & kAnalysisNameMap) {
+    BuildIdToNameMap();
+  }
 }
 
 void IRContext::InvalidateAnalysesExceptFor(
@@ -70,6 +73,9 @@ void IRContext::InvalidateAnalyses(IRContext::Analysis analyses_to_invalidate) {
     dominator_trees_.clear();
     post_dominator_trees_.clear();
   }
+  if (analyses_to_invalidate & kAnalysisNameMap) {
+    id_to_name_.reset(nullptr);
+  }
 
   valid_analyses_ = Analysis(valid_analyses_ & ~analyses_to_invalidate);
 }
@@ -100,6 +106,8 @@ Instruction* IRContext::KillInst(ir::Instruction* inst) {
     type_mgr_->RemoveId(inst->result_id());
   }
 
+  RemoveFromIdToName(inst);
+
   Instruction* next_instruction = nullptr;
   if (inst->IsInAList()) {
     next_instruction = inst->NextNode();
@@ -206,6 +214,7 @@ void spvtools::ir::IRContext::ForgetUses(Instruction* inst) {
       get_decoration_mgr()->RemoveDecoration(inst);
     }
   }
+  RemoveFromIdToName(inst);
 }
 
 void IRContext::AnalyzeUses(Instruction* inst) {
@@ -217,6 +226,10 @@ void IRContext::AnalyzeUses(Instruction* inst) {
       get_decoration_mgr()->AddDecoration(inst);
     }
   }
+  if (id_to_name_ &&
+      (inst->opcode() == SpvOpName || inst->opcode() == SpvOpMemberName)) {
+    id_to_name_->insert({inst->GetSingleWordInOperand(0), inst});
+  }
 }
 
 void IRContext::KillNamesAndDecorates(uint32_t id) {
@@ -227,19 +240,12 @@ void IRContext::KillNamesAndDecorates(uint32_t id) {
     KillInst(inst);
   }
 
-  Instruction* debug_inst = &*debug2_begin();
-  while (debug_inst) {
-    bool killed_inst = false;
-    if (debug_inst->opcode() == SpvOpMemberName ||
-        debug_inst->opcode() == SpvOpName) {
-      if (debug_inst->GetSingleWordInOperand(0) == id) {
-        debug_inst = KillInst(debug_inst);
-        killed_inst = true;
-      }
-    }
-    if (!killed_inst) {
-      debug_inst = debug_inst->NextNode();
-    }
+  std::vector<ir::Instruction*> name_to_kill;
+  for (auto name : GetNames(id)) {
+    name_to_kill.push_back(name.second);
+  }
+  for (ir::Instruction* name_inst : name_to_kill) {
+    KillInst(name_inst);
   }
 }
 
@@ -484,6 +490,19 @@ void IRContext::InitializeCombinators() {
   valid_analyses_ |= kAnalysisCombinators;
 }
 
+void IRContext::RemoveFromIdToName(const Instruction* inst) {
+  if (id_to_name_ &&
+      (inst->opcode() == SpvOpName || inst->opcode() == SpvOpMemberName)) {
+    auto range = id_to_name_->equal_range(inst->GetSingleWordInOperand(0));
+    for (auto it = range.first; it != range.second; ++it) {
+      if (it->second == inst) {
+        id_to_name_->erase(it);
+        break;
+      }
+    }
+  }
+}
+
 ir::LoopDescriptor* IRContext::GetLoopDescriptor(const ir::Function* f) {
   if (!AreAnalysesValid(kAnalysisLoopAnalysis)) {
     ResetLoopAnalysis();
index d209ed3..373bfb0 100644 (file)
@@ -57,7 +57,8 @@ class IRContext {
     kAnalysisCFG = 1 << 4,
     kAnalysisDominatorAnalysis = 1 << 5,
     kAnalysisLoopAnalysis = 1 << 6,
-    kAnalysisEnd = 1 << 7
+    kAnalysisNameMap = 1 << 7,
+    kAnalysisEnd = 1 << 8
   };
 
   friend inline Analysis operator|(Analysis lhs, Analysis rhs);
@@ -75,7 +76,8 @@ class IRContext {
         def_use_mgr_(nullptr),
         valid_analyses_(kAnalysisNone),
         constant_mgr_(nullptr),
-        type_mgr_(nullptr) {
+        type_mgr_(nullptr),
+        id_to_name_(nullptr) {
     libspirv::SetContextMessageConsumer(syntax_context_, consumer_);
     module_->SetContext(this);
   }
@@ -89,8 +91,8 @@ class IRContext {
         consumer_(std::move(c)),
         def_use_mgr_(nullptr),
         valid_analyses_(kAnalysisNone),
-        constant_mgr_(nullptr),
-        type_mgr_(nullptr) {
+        type_mgr_(nullptr),
+        id_to_name_(nullptr) {
     libspirv::SetContextMessageConsumer(syntax_context_, consumer_);
     module_->SetContext(this);
     InitializeCombinators();
@@ -256,6 +258,15 @@ class IRContext {
     return type_mgr_.get();
   }
 
+  // Build the map from the ids to the OpName and OpMemberName instruction
+  // associated with it.
+  inline void BuildIdToNameMap();
+
+  // Returns a range of instrucions that contain all of the OpName and
+  // OpMemberNames associated with the given id.
+  inline IteratorRange<std::multimap<uint32_t, Instruction*>::iterator>
+  GetNames(uint32_t id);
+
   // Sets the message consumer to the given |consumer|. |consumer| which will be
   // invoked every time there is a message to be communicated to the outside.
   void SetMessageConsumer(spvtools::MessageConsumer c) {
@@ -465,6 +476,9 @@ class IRContext {
   // Add the combinator opcode for the given extension to combinator_ops_.
   void AddCombinatorsForExtension(ir::Instruction* extension);
 
+  // Remove |inst| from |id_to_name_| if it is in map.
+  void RemoveFromIdToName(const Instruction* inst);
+
   // The SPIR-V syntax context containing grammar tables for opcodes and
   // operands.
   spv_context syntax_context_;
@@ -523,6 +537,9 @@ class IRContext {
 
   // Type manager for |module_|.
   std::unique_ptr<opt::analysis::TypeManager> type_mgr_;
+
+  // A map from an id to its corresponding OpName and OpMemberName instructions.
+  std::unique_ptr<std::multimap<uint32_t, Instruction*>> id_to_name_;
 };
 
 inline ir::IRContext::Analysis operator|(ir::IRContext::Analysis lhs,
@@ -695,6 +712,11 @@ void IRContext::AddDebug1Inst(std::unique_ptr<Instruction>&& d) {
 }
 
 void IRContext::AddDebug2Inst(std::unique_ptr<Instruction>&& d) {
+  if (AreAnalysesValid(kAnalysisNameMap)) {
+    if (d->opcode() == SpvOpName || d->opcode() == SpvOpMemberName) {
+      id_to_name_->insert({d->result_id(), d.get()});
+    }
+  }
   module()->AddDebug2Inst(std::move(d));
 }
 
@@ -733,6 +755,26 @@ void IRContext::UpdateDefUse(Instruction* inst) {
   }
 }
 
+void IRContext::BuildIdToNameMap() {
+  id_to_name_.reset(new std::multimap<uint32_t, Instruction*>());
+  for (Instruction& debug_inst : debugs2()) {
+    if (debug_inst.opcode() == SpvOpMemberName ||
+        debug_inst.opcode() == SpvOpName) {
+      id_to_name_->insert({debug_inst.GetSingleWordInOperand(0), &debug_inst});
+    }
+  }
+  valid_analyses_ = valid_analyses_ | kAnalysisNameMap;
+}
+
+IteratorRange<std::multimap<uint32_t, Instruction*>::iterator>
+IRContext::GetNames(uint32_t id) {
+  if (!AreAnalysesValid(kAnalysisNameMap)) {
+    BuildIdToNameMap();
+  }
+  auto result = id_to_name_->equal_range(id);
+  return make_range(std::move(result.first), std::move(result.second));
+}
+
 }  // namespace ir
 }  // namespace spvtools
 #endif  // SPIRV_TOOLS_IR_CONTEXT_H
index b599e66..cc83b60 100644 (file)
@@ -38,7 +38,8 @@ class LocalRedundancyEliminationPass : public Pass {
            ir::IRContext::kAnalysisInstrToBlockMapping |
            ir::IRContext::kAnalysisDecorations |
            ir::IRContext::kAnalysisCombinators | ir::IRContext::kAnalysisCFG |
-           ir::IRContext::kAnalysisDominatorAnalysis;
+           ir::IRContext::kAnalysisDominatorAnalysis |
+           ir::IRContext::kAnalysisNameMap;
   }
 
  protected:
index 755a79f..89cd994 100644 (file)
@@ -33,7 +33,8 @@ class PrivateToLocalPass : public Pass {
     return ir::IRContext::kAnalysisDefUse |
            ir::IRContext::kAnalysisDecorations |
            ir::IRContext::kAnalysisCombinators | ir::IRContext::kAnalysisCFG |
-           ir::IRContext::kAnalysisDominatorAnalysis;
+           ir::IRContext::kAnalysisDominatorAnalysis |
+           ir::IRContext::kAnalysisNameMap;
   }
 
  private:
@@ -43,18 +44,19 @@ class PrivateToLocalPass : public Pass {
 
   // |inst| is an instruction declaring a varible.  If that variable is
   // referenced in a single function and all of uses are valid as defined by
-  // |IsValidUse|, then that function is returned.  Otherwise, the return value
-  // is |nullptr|.
+  // |IsValidUse|, then that function is returned.  Otherwise, the return
+  // value is |nullptr|.
   ir::Function* FindLocalFunction(const ir::Instruction& inst) const;
 
-  // Returns true is |inst| is a valid use of a pointer.  In this case, a valid
-  // use is one where the transformation is able to rewrite the type to match a
-  // change in storage class of the original variable.
+  // Returns true is |inst| is a valid use of a pointer.  In this case, a
+  // valid use is one where the transformation is able to rewrite the type to
+  // match a change in storage class of the original variable.
   bool IsValidUse(const ir::Instruction* inst) const;
 
-  // Given the result id of a pointer type, |old_type_id|, this function returns
-  // the id of a the same pointer type except the storage class has been changed
-  // to function.  If the type does not already exist, it will be created.
+  // Given the result id of a pointer type, |old_type_id|, this function
+  // returns the id of a the same pointer type except the storage class has
+  // been changed to function.  If the type does not already exist, it will be
+  // created.
   uint32_t GetNewType(uint32_t old_type_id);
 
   // Updates |inst|, and any instruction dependent on |inst|, to reflect the
index 47542f9..a48174f 100644 (file)
@@ -39,7 +39,8 @@ class ScalarReplacementPass : public Pass {
     return ir::IRContext::kAnalysisDefUse |
            ir::IRContext::kAnalysisInstrToBlockMapping |
            ir::IRContext::kAnalysisDecorations |
-           ir::IRContext::kAnalysisCombinators | ir::IRContext::kAnalysisCFG;
+           ir::IRContext::kAnalysisCombinators | ir::IRContext::kAnalysisCFG |
+           ir::IRContext::kAnalysisNameMap;
   }
 
  private: