Move some function definitions from header to source to avoid circular definition.
if (set & kAnalysisDominatorAnalysis) {
ResetDominatorAnalysis();
}
+ if (set & kAnalysisLoopAnalysis) {
+ ResetLoopAnalysis();
+ }
}
void IRContext::InvalidateAnalysesExceptFor(
valid_analyses_ |= kAnalysisCombinators;
}
+ir::LoopDescriptor* IRContext::GetLoopDescriptor(const ir::Function* f) {
+ if (!AreAnalysesValid(kAnalysisLoopAnalysis)) {
+ ResetLoopAnalysis();
+ }
+
+ std::unordered_map<const ir::Function*, ir::LoopDescriptor>::iterator it =
+ loop_descriptors_.find(f);
+ if (it == loop_descriptors_.end()) {
+ return &loop_descriptors_.emplace(std::make_pair(f, ir::LoopDescriptor(f)))
+ .first->second;
+ }
+
+ return &it->second;
+}
+
// Gets the dominator analysis for function |f|.
opt::DominatorAnalysis* IRContext::GetDominatorAnalysis(const ir::Function* f,
const ir::CFG& in_cfg) {
#include "def_use_manager.h"
#include "dominator_analysis.h"
#include "feature_manager.h"
+#include "loop_descriptor.h"
#include "module.h"
#include "type_manager.h"
kAnalysisCombinators = 1 << 3,
kAnalysisCFG = 1 << 4,
kAnalysisDominatorAnalysis = 1 << 5,
- kAnalysisEnd = 1 << 6
+ kAnalysisLoopAnalysis = 1 << 6,
+ kAnalysisEnd = 1 << 7
};
friend inline constexpr Analysis operator|(Analysis lhs, Analysis rhs);
return cfg_.get();
}
+ // Gets the loop descriptor for function |f|.
+ ir::LoopDescriptor* GetLoopDescriptor(const ir::Function* f);
+
// Gets the dominator analysis for function |f|.
opt::DominatorAnalysis* GetDominatorAnalysis(const ir::Function* f,
const ir::CFG&);
valid_analyses_ = valid_analyses_ | kAnalysisDominatorAnalysis;
}
+ // Removes all computed loop descriptors.
+ void ResetLoopAnalysis() {
+ // Clear the cache.
+ loop_descriptors_.clear();
+ valid_analyses_ = valid_analyses_ | kAnalysisLoopAnalysis;
+ }
+
// Analyzes the features in the owned module. Builds the manager if required.
void AnalyzeFeatures() {
feature_mgr_.reset(new opt::FeatureManager(grammar_));
std::map<const ir::Function*, opt::PostDominatorAnalysis>
post_dominator_trees_;
+ // Cache of loop descriptors for each function.
+ std::unordered_map<const ir::Function*, ir::LoopDescriptor> loop_descriptors_;
+
// Constant manager for |module_|.
std::unique_ptr<opt::analysis::ConstantManager> constant_mgr_;
#include <utility>
#include <vector>
+#include "opt/cfg.h"
+#include "opt/dominator_tree.h"
+#include "opt/ir_context.h"
#include "opt/iterator.h"
#include "opt/loop_descriptor.h"
#include "opt/make_unique.h"
return nullptr;
}
+bool Loop::IsInsideLoop(Instruction* inst) const {
+ const BasicBlock* parent_block = inst->context()->get_instr_block(inst);
+ if (!parent_block) return false;
+ return IsInsideLoop(parent_block);
+}
+
+bool Loop::IsBasicBlockInLoopSlow(const BasicBlock* bb) {
+ assert(bb->GetParent() && "The basic block does not belong to a function");
+ IRContext* context = bb->GetParent()->GetParent()->context();
+
+ opt::DominatorAnalysis* dom_analysis =
+ context->GetDominatorAnalysis(bb->GetParent(), *context->cfg());
+ if (!dom_analysis->Dominates(GetHeaderBlock(), bb)) return false;
+
+ opt::PostDominatorAnalysis* postdom_analysis =
+ context->GetPostDominatorAnalysis(bb->GetParent(), *context->cfg());
+ if (!postdom_analysis->Dominates(GetMergeBlock(), bb)) return false;
+ return true;
+}
+
LoopDescriptor::LoopDescriptor(const Function* f) { PopulateList(f); }
void LoopDescriptor::PopulateList(const Function* f) {
#include <unordered_set>
#include <vector>
-#include "opt/module.h"
-#include "opt/pass.h"
+#include "opt/basic_block.h"
#include "opt/tree_iterator.h"
namespace spvtools {
+namespace opt {
+class DominatorAnalysis;
+struct DominatorTreeNode;
+} // namespace opt
namespace ir {
+class IRContext;
class CFG;
class LoopDescriptor;
}
// Returns true if the instruction |inst| is inside this loop.
- inline bool IsInsideLoop(Instruction* inst) const {
- const BasicBlock* parent_block = inst->context()->get_instr_block(inst);
- if (!parent_block) return true;
- return IsInsideLoop(parent_block);
- }
+ bool IsInsideLoop(Instruction* inst) const;
// Adds the Basic Block |bb| this loop and its parents.
void AddBasicBlockToLoop(const BasicBlock* bb) {
-#ifndef NDEBUG
- assert(bb->GetParent() && "The basic block does not belong to a function");
- IRContext* context = bb->GetParent()->GetParent()->context();
-
- opt::DominatorAnalysis* dom_analysis =
- context->GetDominatorAnalysis(bb->GetParent(), *context->cfg());
- assert(dom_analysis->Dominates(GetHeaderBlock(), bb));
-
- opt::PostDominatorAnalysis* postdom_analysis =
- context->GetPostDominatorAnalysis(bb->GetParent(), *context->cfg());
- assert(postdom_analysis->Dominates(GetMergeBlock(), bb));
-#endif // NDEBUG
+ assert(IsBasicBlockInLoopSlow(bb) &&
+ "Basic block does not belong to the loop");
for (Loop* loop = this; loop != nullptr; loop = loop->parent_) {
loop_basic_blocks_.insert(bb->id());
// computed only when needed on demand.
BasicBlockListTy loop_basic_blocks_;
+ // Check that |bb| is inside the loop using domination properties.
+ // Note: this is for assertion purposes only, IsInsideLoop should be used
+ // instead.
+ bool IsBasicBlockInLoopSlow(const BasicBlock* bb);
+
// Sets the parent loop of this loop, that is, a loop which contains this loop
// as a nested child loop.
inline void SetParent(Loop* parent) { parent_ = parent; }
EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
<< text << std::endl;
const ir::Function* f = spvtest::GetFunction(module, 2);
- ir::LoopDescriptor ld{f};
+ ir::LoopDescriptor& ld = *context->GetLoopDescriptor(f);
EXPECT_EQ(ld.NumLoops(), 1u);
EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
<< text << std::endl;
const ir::Function* f = spvtest::GetFunction(module, 2);
- ir::LoopDescriptor ld{f};
+ ir::LoopDescriptor& ld = *context->GetLoopDescriptor(f);
EXPECT_EQ(ld.NumLoops(), 2u);
EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
<< text << std::endl;
const ir::Function* f = spvtest::GetFunction(module, 2);
- ir::LoopDescriptor ld{f};
+ ir::LoopDescriptor& ld = *context->GetLoopDescriptor(f);
EXPECT_EQ(ld.NumLoops(), 3u);
EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
<< text << std::endl;
const ir::Function* f = spvtest::GetFunction(module, 2);
- ir::LoopDescriptor ld{f};
+ ir::LoopDescriptor& ld = *context->GetLoopDescriptor(f);
EXPECT_EQ(ld.NumLoops(), 4u);
EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
<< text << std::endl;
const ir::Function* f = spvtest::GetFunction(module, 2);
- ir::LoopDescriptor ld{f};
+ ir::LoopDescriptor& ld = *context->GetLoopDescriptor(f);
EXPECT_EQ(ld.NumLoops(), 4u);