Skip to content

Commit

Permalink
Add LoopDescriptor as an IRContext analysis.
Browse files Browse the repository at this point in the history
Move some function definitions from header to source to avoid circular definition.
  • Loading branch information
Naghasan authored and s-perron committed Jan 25, 2018
1 parent 684997e commit 6018de8
Show file tree
Hide file tree
Showing 6 changed files with 76 additions and 25 deletions.
18 changes: 18 additions & 0 deletions source/opt/ir_context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ void IRContext::BuildInvalidAnalyses(IRContext::Analysis set) {
if (set & kAnalysisDominatorAnalysis) {
ResetDominatorAnalysis();
}
if (set & kAnalysisLoopAnalysis) {
ResetLoopAnalysis();
}
}

void IRContext::InvalidateAnalysesExceptFor(
Expand Down Expand Up @@ -483,6 +486,21 @@ void IRContext::InitializeCombinators() {
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) {
Expand Down
17 changes: 16 additions & 1 deletion source/opt/ir_context.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include "def_use_manager.h"
#include "dominator_analysis.h"
#include "feature_manager.h"
#include "loop_descriptor.h"
#include "module.h"
#include "type_manager.h"

Expand Down Expand Up @@ -55,7 +56,8 @@ class IRContext {
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);
Expand Down Expand Up @@ -363,6 +365,9 @@ class IRContext {
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&);
Expand Down Expand Up @@ -433,6 +438,13 @@ class IRContext {
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_));
Expand Down Expand Up @@ -499,6 +511,9 @@ class IRContext {
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_;

Expand Down
23 changes: 23 additions & 0 deletions source/opt/loop_descriptor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@
#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"
Expand Down Expand Up @@ -80,6 +83,26 @@ BasicBlock* Loop::FindLoopPreheader(IRContext* ir_context,
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) {
Expand Down
33 changes: 14 additions & 19 deletions source/opt/loop_descriptor.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,16 @@
#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;

Expand Down Expand Up @@ -128,26 +132,12 @@ class Loop {
}

// 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());
Expand Down Expand Up @@ -177,6 +167,11 @@ class Loop {
// 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; }
Expand Down
4 changes: 2 additions & 2 deletions test/opt/loop_optimizations/loop_descriptions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ TEST_F(PassClassTest, BasicVisitFromEntryPoint) {
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);

Expand Down Expand Up @@ -194,7 +194,7 @@ TEST_F(PassClassTest, LoopWithNoPreHeader) {
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);

Expand Down
6 changes: 3 additions & 3 deletions test/opt/loop_optimizations/nested_loops.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ TEST_F(PassClassTest, BasicVisitFromEntryPoint) {
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);

Expand Down Expand Up @@ -331,7 +331,7 @@ TEST_F(PassClassTest, TripleNestedLoop) {
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);

Expand Down Expand Up @@ -555,7 +555,7 @@ TEST_F(PassClassTest, LoopParentTest) {
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);

Expand Down

0 comments on commit 6018de8

Please sign in to comment.