diff --git a/src/analysis/function_analysis.cpp b/src/analysis/function_analysis.cpp index faf323be604b7996d6adccdb51c8968153daeab2..32ffc4f79462abedd20f67e0cc3ee784bf8a15dc 100644 --- a/src/analysis/function_analysis.cpp +++ b/src/analysis/function_analysis.cpp @@ -18,6 +18,9 @@ #include <unordered_set> #include <deque> +#include <llvm/ADT/SetVector.h> +#include <llvm/ADT/SmallSet.h> + #include "core/common.h" #include "core/ast.h" @@ -32,7 +35,7 @@ namespace pyston { class LivenessBBVisitor : public NoopASTVisitor { public: - typedef std::unordered_set<std::string> StrSet; + typedef llvm::SmallSet<std::string, 4> StrSet; private: StrSet _loads; @@ -91,10 +94,11 @@ bool LivenessAnalysis::isLiveAtEnd(const std::string& name, CFGBlock* block) { // for each query, trace forward through all possible control flow paths. // if we hit a store to the name, stop tracing that path // if we hit a load to the name, return true. - std::unordered_set<CFGBlock*> visited; + // to improve performance we cache the liveness result of every visited BB. + llvm::SmallPtrSet<CFGBlock*, 1> visited; std::deque<CFGBlock*> q; - for (int i = 0; i < block->successors.size(); i++) { - q.push_back(block->successors[i]); + for (CFGBlock* successor : block->successors) { + q.push_back(successor); } while (q.size()) { @@ -102,22 +106,29 @@ bool LivenessAnalysis::isLiveAtEnd(const std::string& name, CFGBlock* block) { q.pop_front(); if (visited.count(thisblock)) continue; - visited.insert(thisblock); - LivenessBBVisitor visitor; - for (int i = 0; i < thisblock->body.size(); i++) { - thisblock->body[i]->accept(&visitor); + LivenessBBVisitor* visitor = nullptr; + LivenessCacheMap::iterator it = livenessCache.find(thisblock); + if (it != livenessCache.end()) { + visitor = it->second.get(); + } else { + visitor = new LivenessBBVisitor; // livenessCache unique_ptr will delete it. + for (AST_stmt* stmt : thisblock->body) { + stmt->accept(visitor); + } + livenessCache.insert(std::make_pair(thisblock, std::unique_ptr<LivenessBBVisitor>(visitor))); } + visited.insert(thisblock); - if (visitor.loads().count(name)) { - assert(!visitor.stores().count(name)); + if (visitor->loads().count(name)) { + assert(!visitor->stores().count(name)); return true; } - if (!visitor.stores().count(name)) { - assert(!visitor.loads().count(name)); - for (int i = 0; i < thisblock->successors.size(); i++) { - q.push_back(thisblock->successors[i]); + if (!visitor->stores().count(name)) { + assert(!visitor->loads().count(name)); + for (CFGBlock* successor : thisblock->successors) { + q.push_back(successor); } } } diff --git a/src/analysis/function_analysis.h b/src/analysis/function_analysis.h index 50e7e15d01dfaed50de8c2534b289bbea04b9450..b0108f8b61554dafb6bc5e8794f1c65f84ac6594 100644 --- a/src/analysis/function_analysis.h +++ b/src/analysis/function_analysis.h @@ -25,10 +25,15 @@ class AST_Jump; class CFG; class CFGBlock; class ScopeInfo; +class LivenessBBVisitor; class LivenessAnalysis { public: bool isLiveAtEnd(const std::string& name, CFGBlock* block); + +private: + typedef std::unordered_map<CFGBlock*, std::unique_ptr<LivenessBBVisitor> > LivenessCacheMap; + LivenessCacheMap livenessCache; }; class DefinednessAnalysis { public: