Page Menu
Home
Xreate
Search
Configure Global Search
Log In
Docs
Questions
Repository
Issues
Patches
Internal API
Files
F2718310
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Subscribers
None
File Metadata
Details
File Info
Storage
Attached
Created
Sun, Feb 15, 11:42 PM
Size
57 KB
Mime Type
text/x-diff
Expires
Tue, Feb 17, 11:42 PM (1 d, 14 h)
Engine
blob
Format
Raw Data
Handle
237844
Attached To
rXR Xreate
View Options
diff --git a/config/default.json b/config/default.json
index 338ac69..862b37e 100644
--- a/config/default.json
+++ b/config/default.json
@@ -1,73 +1,72 @@
{
"containers": {
"id": {
"implementations": "impl_fulfill_cluster",
"clusters": "var_cluster",
"prototypes": "proto_cluster",
"linkedlist": "linkedlist"
},
"impl": {
"solid": "solid",
"onthefly": "on_the_fly"
}
},
"logging": {
"id": "logging"
},
"function-entry": "entry",
"clasp": {
"bindings" : {
"variable": "bind",
"function": "bind_func",
"scope": "bind_scope",
"function_demand" : "bind_function_demand",
"scope_decision": "bind_scope_decision"
},
"context" : {
"decisions":{
"dependent": "resolution_dependency"
}
},
"nonevalue": "nonevalue",
"ret": {
"symbol": "retv",
"tag": "ret"
}
},
"tests": {
- "template": "sequence",
+ "template": "current-fix",
"templates": {
- "sequence": "Compilation.Sequence1",
- "current-fix":"",
+ "current-fix":"CFA.DomReportOneRoot",
"default": "*-Adhoc.*:Containers.*:Compilation.full_IFStatementWithVariantType:Types.full_VariantType_Switch1:Context.full_LateContext:Context.pathDependentContext",
"ast": "AST.*",
"adhocs": "Adhoc.*",
"effects": "Effects.*",
"basic": "Attachments.*",
"context": "Context.*",
"compilation": "Compilation.*-Compilation.full_IFStatementWithVariantType",
"communication": "Communication.*",
"cfa": "CFA.*",
"containers": "Containers.*",
"dfa": "DFA.*",
"diagnostic": "Diagnostic.*",
"dsl": "Association.*:Interpretation.SwitchVariantAlias",
"ExpressionSerializer": "ExpressionSerializer.*",
"externc": "InterfaceExternC.*",
"loops": "Loop.*",
"modules": "Modules.*",
"polymorphs": "Polymorphs.call1",
"types": "Types.*",
"vendorsAPI/clang": "ClangAPI.*",
"vendorsAPI/xml2": "libxml2*"
}
}
}
diff --git a/cpp/src/analysis/DominatorsTreeAnalysisProvider.cpp b/cpp/src/analysis/DominatorsTreeAnalysisProvider.cpp
index c6a928b..4aaab5b 100644
--- a/cpp/src/analysis/DominatorsTreeAnalysisProvider.cpp
+++ b/cpp/src/analysis/DominatorsTreeAnalysisProvider.cpp
@@ -1,239 +1,241 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* File: DominatorsTreeAnalysisProvider.cpp
* Author: pgess <v.melnychenko@xreate.org>
*
* Created on May 13, 2016, 11:39 AM
*/
/**
* \file DominatorsTreeAnalysisProvider.h
* \brief Dominators Tree analysis
*/
#include "analysis/cfagraph.h"
#include "analysis/DominatorsTreeAnalysisProvider.h"
#include "llvm/ADT/GraphTraits.h"
#include "llvm/Support/GenericDomTreeConstruction.h"
#include "llvm/Support/GenericDomTree.h"
#include <list>
#include <iostream>
#include <boost/format.hpp>
using namespace std;
using namespace xreate;
using namespace boost;
using namespace boost::bimaps;
-namespace xreate{ namespace dominators {
+namespace xreate {
+namespace dominators {
-struct ControlFlowTree;
-struct Node {
- ScopePacked scope;
- ControlFlowTree* tree;
+struct CFAGraphAdapter;
+
+struct ScopeNode {
+ ScopePacked id;
+ std::list<ScopeNode*> nodesFrom;
+ std::list<ScopeNode*> nodesTo;
};
-/*
-bool operator !=(const Node& a, const Node& b){
- return (a.tree != b.tree) || (a.scope != b.scope);
-}
+struct CFAGraphAdapter {
+ std::list<ScopeNode> nodes;
+ ScopeNode* nodeRoot;
-Node& operator++(Node& a){
- ++a.scope;
- return a;
-}
- */
+ ScopeNode* getOrCreateNode(ScopePacked id){
+ ScopeNode elemNew; elemNew.id = id;
+ auto fnComp = [](const ScopeNode &a, const ScopeNode &b){return a.id < b.id;};
+ auto posLowerBound = std::lower_bound(nodes.begin(), nodes.end(), elemNew, fnComp);
-struct ControlFlowTree{
- typedef bimap<multiset_of<ScopePacked>, multiset_of<ScopePacked>> CHILD_RELATIONS;
- CHILD_RELATIONS edges;
- std::vector<Node> nodes;
- Node* entry = nullptr;
- size_t size;
+ if(posLowerBound==nodes.end()|| posLowerBound->id > id){
+ return &*nodes.insert(posLowerBound, elemNew);
+ }
- ControlFlowTree(const size_t nodesCount): nodes(nodesCount), size(nodesCount){
+ return &*posLowerBound;
}
- static ControlFlowTree* build(const ClaspLayer* engine, cfa::CFAGraph* graph){
- ControlFlowTree* tree = new ControlFlowTree(engine->getScopesCount());
+ static CFAGraphAdapter* build(const cfa::CFAGraph* graph) {
+ CFAGraphAdapter* tree=new CFAGraphAdapter();
- for (const auto& edge: graph->__parentScopeRelations){
- tree->edges.insert(CHILD_RELATIONS::value_type(edge.second, edge.first));
- }
+ enum NODE_MARK{NO_ROOT, POSSIBLE_ROOT};
+ std::unordered_map<unsigned int, NODE_MARK> nodeMarks;
+ for (const auto& edge: graph->__dependencyRelations){
- for (const auto& edge: graph->__callRelations){
- unsigned int calleeFunction = edge.right;
- ScopePacked caller = edge.left;
+ ScopeNode* nodeTo = tree->getOrCreateNode(edge.first);
+ ScopeNode* nodeFrom = tree->getOrCreateNode(edge.second);
+ nodeTo->nodesFrom.push_back(nodeFrom);
+ nodeFrom->nodesTo.push_back(nodeTo);
- auto range = graph->__parentFunctionRelations.right.equal_range(calleeFunction);
- for (auto& i=range.first; i!= range.second; ++i){
- tree->edges.insert(CHILD_RELATIONS::value_type(caller, i->second));
+ nodeMarks.emplace(edge.second, POSSIBLE_ROOT); //weak optional insert
+ auto result = nodeMarks.emplace(edge.first, NO_ROOT); //strong insert or update
+ if(!result.second){
+ result.first->second = NO_ROOT;
}
}
- for (size_t i=0; i<tree->size; ++i){
- tree->nodes[i]= Node{(unsigned int) i, tree};
+ std::list<ScopePacked> nodeRoots;
+ for(auto nodeMark: nodeMarks){
+ if(nodeMark.second == POSSIBLE_ROOT) nodeRoots.push_back(nodeMark.first);
}
- return tree;
- }
-
- std::list<unsigned int> getRootFunctions() const{
- size_t idMax = size;
- size_t id =0;
- std::list<unsigned int> results;
- auto i = edges.right.begin();
-
- while (id < idMax) {
- if (i!= edges.right.end() && i->first == id){
- i = edges.right.upper_bound(i->first);
-
- } else {
- results.push_back(id);
+ if(nodeRoots.size()>1){
+ ScopeNode* nodeGlobalRoot = tree->getOrCreateNode(SCOPE_ABSTRACT_GLOBAL);
+ for(auto rootLocal: nodeRoots){
+ ScopeNode* nodeLocalRoot = tree->getOrCreateNode(rootLocal);
+ nodeLocalRoot->nodesFrom.push_back(nodeGlobalRoot);
+ nodeGlobalRoot->nodesTo.push_back(nodeLocalRoot);
}
-
- ++id;
+ } else {
+ assert(nodeRoots.size()==1);
+ tree->nodeRoot = tree->getOrCreateNode(nodeRoots.front());
}
- return std::move(results);
+ return tree;
}
+
+ CFAGraphAdapter() { }
};
-}} //end of namespace xreate::dominators
+}
+} //end of namespace xreate::dominators
namespace llvm {
- using namespace xreate::dominators;
-
- template <> struct GraphTraits<Node*> {
- typedef Node* nodes_iterator;
- typedef Node NodeType;
-
- typedef std::function<Node*(ControlFlowTree::CHILD_RELATIONS::left_value_type)> Transformer;
- typedef typename boost::transform_iterator<Transformer, ControlFlowTree::CHILD_RELATIONS::left_iterator> ChildIteratorType;
-
- static ChildIteratorType child_begin(const nodes_iterator& node) {
- auto range = node->tree->edges.left.equal_range(node->scope);
- Transformer x = [node](auto edge){return &node->tree->nodes[edge.second];};
-
- return boost::make_transform_iterator(range.first, x);
- }
+using namespace xreate::dominators;
- static ChildIteratorType child_end(const nodes_iterator& node) {
- auto range = node->tree->edges.left.equal_range(node->scope);
- Transformer x = [node](auto edge){return &node->tree->nodes[edge.second];};
+template<>
+struct GraphTraits<ScopeNode*> {
+ typedef ScopeNode NodeType;
+ typedef std::list<ScopeNode*>::iterator ChildIteratorType;
- return boost::make_transform_iterator(range.second, x);
- }
- };
+ static ChildIteratorType
+ child_begin(NodeType* node) {
+ return node->nodesTo.begin();
+ }
- template <> struct GraphTraits<Inverse<Node*>> {
- typedef Node* nodes_iterator;
- typedef Node NodeType;
+ static ChildIteratorType
+ child_end(NodeType* node) {
+ return node->nodesTo.end();
+ }
+};
- typedef std::function<Node*(ControlFlowTree::CHILD_RELATIONS::right_value_type)> Transformer;
- typedef typename boost::transform_iterator<Transformer, ControlFlowTree::CHILD_RELATIONS::right_iterator> ChildIteratorType;
+template<>
+struct GraphTraits<CFAGraphAdapter*> : public GraphTraits<ScopeNode*> {
+ typedef std::list<ScopeNode>::iterator nodes_iterator;
- static ChildIteratorType child_begin(const nodes_iterator& node) {
- auto range = node->tree->edges.right.equal_range(node->scope);
- Transformer x = [node](auto edge){return &node->tree->nodes[edge.second];};
+ static nodes_iterator
+ nodes_begin(CFAGraphAdapter* graph) {
+ return graph->nodes.begin();
+ }
- return boost::make_transform_iterator(range.first, x);
- }
+ static nodes_iterator
+ nodes_end(CFAGraphAdapter* graph) {
+ return graph->nodes.end();
+ }
- static ChildIteratorType child_end(const nodes_iterator& node) {
- auto range = node->tree->edges.right.equal_range(node->scope);
- Transformer x = [node](auto edge){return &node->tree->nodes[edge.second];};
+ static NodeType*
+ getEntryNode(CFAGraphAdapter* F) {
+ return F->nodeRoot;
+ }
- return boost::make_transform_iterator(range.second, x);
- }
- };
+ static unsigned int
+ size(CFAGraphAdapter* graph) {
+ return graph->nodes.size();
+ }
+};
- template <> struct GraphTraits<ControlFlowTree*>: public GraphTraits<Node*> {
- static NodeType*
- getEntryNode(ControlFlowTree* F) {
- if (F->entry) return F->entry;
- list<unsigned int>&& roots = F->getRootFunctions();
- assert(roots.size()==1);
+template<>
+struct GraphTraits<Inverse<ScopeNode*>>
+{
+ typedef ScopeNode NodeType;
+ typedef std::list<ScopeNode*>::iterator ChildIteratorType;
- return F->entry = &F->nodes[roots.front()];
- }
+ static ChildIteratorType
+ child_begin(NodeType* node) {
+ return node->nodesFrom.begin();
+ }
- static nodes_iterator nodes_begin(ControlFlowTree* F) { return &F->nodes[0]; }
- static nodes_iterator nodes_end(ControlFlowTree* F) { return &F->nodes[F->size]; }
- static size_t size(ControlFlowTree* F) { return F->size; }
- };
+ static ChildIteratorType
+ child_end(NodeType* node) {
+ return node->nodesFrom.end();
+ }
+};
}
-namespace xreate{ namespace dominators {
-class DominatorTree: public llvm::DominatorTreeBase<Node> {
+namespace xreate {
+namespace dominators {
+
+class DominatorTree : public llvm::DominatorTreeBase<ScopeNode> {
public:
DominatorsTreeAnalysisProvider::Dominators dominators;
- DominatorTree(bool isPostDom): llvm::DominatorTreeBase<Node>(isPostDom) {}
+ DominatorTree(bool isPostDom) : llvm::DominatorTreeBase<ScopeNode>(isPostDom) { }
- void run(ControlFlowTree& program){
+ void
+ run(CFAGraphAdapter& program) {
recalculate(program);
//extract dominators info
- for (auto& entry: DomTreeNodes){
- if (!entry.getFirst()) continue;
+ for(auto& entry : DomTreeNodes) {
+ if(!entry.getFirst()) continue;
- dominators.emplace(entry.getFirst()->scope, make_pair(entry.getSecond()->getDFSNumIn(), entry.getSecond()->getDFSNumOut()));
+ dominators.emplace(entry.getFirst()->id, make_pair(entry.getSecond()->getDFSNumIn(), entry.getSecond()->getDFSNumOut()));
}
}
- void print(std::ostringstream& output, const std::string& atom) const {
- boost::format formatAtom(atom + "(%1%, range(%2%, %3%)).");
- for (auto entry: dominators){
- output << formatAtom % (entry.first) % (entry.second.first) % (entry.second.second)
- << endl;
+ void
+ print(std::ostringstream& output, const std::string& atom) const {
+ boost::format formatAtom(atom+"(%1%, range(%2%, %3%)).");
+
+ for(auto entry : dominators) {
+ output<<formatAtom%(entry.first)%(entry.second.first)%(entry.second.second)
+ <<endl;
}
}
};
void
-DominatorsTreeAnalysisProvider::run(const ClaspLayer* engine, cfa::CFAGraph* graph){
- boost::scoped_ptr<ControlFlowTree> program(ControlFlowTree::build(engine, graph));
+DominatorsTreeAnalysisProvider::run(const cfa::CFAGraph* graph) {
+ boost::scoped_ptr<CFAGraphAdapter> program(CFAGraphAdapter::build(graph));
- treeForwardDominators->run(*program);
- treePostDominators->run(*program);
+ treeForwardDominators->run(*program);
+ treePostDominators->run(*program);
}
void
-DominatorsTreeAnalysisProvider::print(std::ostringstream& output) const{
+DominatorsTreeAnalysisProvider::print(std::ostringstream& output) const {
treeForwardDominators->print(output, "cfa_forwdom");
treePostDominators->print(output, "cfa_postdom");
}
const DominatorsTreeAnalysisProvider::Dominators&
-DominatorsTreeAnalysisProvider::getForwardDominators() const{
+DominatorsTreeAnalysisProvider::getForwardDominators() const {
return treeForwardDominators->dominators;
}
const DominatorsTreeAnalysisProvider::Dominators&
-DominatorsTreeAnalysisProvider::getPostDominators() const{
+DominatorsTreeAnalysisProvider::getPostDominators() const {
return treePostDominators->dominators;
}
DominatorsTreeAnalysisProvider::DominatorsTreeAnalysisProvider()
- : treeForwardDominators(new DominatorTree(false))
- , treePostDominators(new DominatorTree(true))
-{}
+: treeForwardDominators(new DominatorTree(false))
+, treePostDominators(new DominatorTree(true)) { }
+
+DominatorsTreeAnalysisProvider::~DominatorsTreeAnalysisProvider() { }
+
+}
+} //end of namespace xreate::dominators
-DominatorsTreeAnalysisProvider::~DominatorsTreeAnalysisProvider() {}
-}} //end of namespace xreate::dominators
//void
//CodeScopesTree::print(){
// typedef llvm::GraphTraits<Node*> Traits;
// for (size_t i=0; i<size; ++i){
//
// for (auto j = Traits::child_begin(&nodes[i]); j!= Traits::child_end(&nodes[i]); ++j){
// cout << i << "->" << (*j)->scope << endl;
// }
// }
//}
diff --git a/cpp/src/analysis/DominatorsTreeAnalysisProvider.h b/cpp/src/analysis/DominatorsTreeAnalysisProvider.h
index f0223c6..f284208 100644
--- a/cpp/src/analysis/DominatorsTreeAnalysisProvider.h
+++ b/cpp/src/analysis/DominatorsTreeAnalysisProvider.h
@@ -1,42 +1,42 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* File: DominatorsTreeAnalysisProvider.h
* Author: pgess <v.melnychenko@xreate.org>
*
* Created on May 13, 2016, 11:39 AM
*/
#ifndef DOMINATORSTREEANALYSISPROVIDER_H
#define DOMINATORSTREEANALYSISPROVIDER_H
#include "clasplayer.h"
#include <boost/smart_ptr/scoped_ptr.hpp>
namespace xreate{namespace dominators{
class DominatorTree;
/** \brief Dominators Analysis report */
class DominatorsTreeAnalysisProvider: public IAnalysisReport {
public:
typedef std::pair<ScopePacked, ScopePacked> DominatedRange;
typedef std::map<ScopePacked, DominatedRange> Dominators;
DominatorsTreeAnalysisProvider();
virtual ~DominatorsTreeAnalysisProvider();
- void run(const ClaspLayer* engine, cfa::CFAGraph* graph);
+ void run(const cfa::CFAGraph* graph);
void print(std::ostringstream& output) const override;
const Dominators& getForwardDominators() const;
const Dominators& getPostDominators() const;
private:
boost::scoped_ptr<DominatorTree> treeForwardDominators;
boost::scoped_ptr<DominatorTree> treePostDominators;
};
}} //end of namespace xreate::dominators
#endif /* DOMINATORSTREEANALYSISPROVIDER_H */
diff --git a/cpp/src/analysis/cfagraph.cpp b/cpp/src/analysis/cfagraph.cpp
index cd37e58..3ca5e39 100644
--- a/cpp/src/analysis/cfagraph.cpp
+++ b/cpp/src/analysis/cfagraph.cpp
@@ -1,175 +1,204 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* File: CFAGraph.cpp
* Author: pgess <v.melnychenko@xreate.org>
*
* Created on June 27, 2016, 2:09 PM
*/
/**
* \file cfagraph.h
* \brief Control Flow Analysis(CFA) graph data
*
*/
#include "analysis/cfagraph.h"
#include "analysis/aux.h"
using namespace xreate::cfa;
using namespace std;
void
CFAGraph::print(std::ostringstream& output) const {
const std::string& atomBinding = Config::get("clasp.bindings.function");
const std::string& atomBindingScope = Config::get("clasp.bindings.scope");
//show function tags
int counterTags = 0;
std::ostringstream bufFunctionNames;
boost::format formatFunction("function(%1%).");
boost::format formatBind(atomBinding + "(%1%, %2%).");
for (auto function: this->__nodesFunction.left) {
const auto tags = this->__functionTags.equal_range(function.first);
if (tags.first == tags.second) {
//no tags
bufFunctionNames << "; " << function.second ;
continue;
}
output << formatFunction % (function.second) << std::endl;
for (const auto& tag_: boost::make_iterator_range(tags)){
const Expression& tag = tag_.second;
list<string> tagRaw = xreate::analysis::compile(tag);
assert(tagRaw.size() == 1);
output << formatBind
% (function.second)
% (tagRaw.front())
<< endl;
++counterTags;
}
}
if (bufFunctionNames.tellp()){
output << formatFunction % (bufFunctionNames.str().substr(2)) << std::endl;
}
if (counterTags == 0) {
output << "%no functtion tags at all" << endl;
}
//declare scopes
boost::format formatScope("scope(0..%1%).");
output << formatScope % (__clasp->getScopesCount() - 1) << std::endl;
//show context rules:
for (auto rule: this->__contextRules) {
output << ContextRule(rule.second).compile(rule.first) << std::endl;
};
//show scope tags:
counterTags = 0;
boost::format formatScopeBind(atomBindingScope + "(%1%, %2%, strong).");
for (auto entry: this->__scopeTags) {
ScopePacked scopeId = entry.first;
const Expression& tag = entry.second;
list<string> tagRaw = xreate::analysis::compile(tag);
assert(tagRaw.size() == 1);
output << formatScopeBind % scopeId %(tagRaw.front()) << endl;
++counterTags;
}
if (counterTags == 0) {
output << "%scope tags: no tags at all" << endl;
}
output << endl << "%\t\tStatic analysis: CFA" << endl;
//parent connections
//TOTEST CFG parent function
boost::format formatFunctionParent("cfa_parent(%1%, function(%2%)).");
for (const auto &relation: this->__parentFunctionRelations) {
const string& function = this->__nodesFunction.left.at(relation.right);
output << formatFunctionParent % relation.left % function << endl;
}
//TOTEST CFG parent scope
boost::format formatScopeParent("cfa_parent(%1%, scope(%2%)).");
for (const auto &relation: this->__parentScopeRelations) {
output << formatScopeParent % relation.first % relation.second << endl;
}
//call connections
boost::format formatCall("cfa_call(%1%, %2%).");
for (const auto &relation: this->__callRelations) {
const ScopePacked scopeFrom = relation.left;
const string& functionTo = this->__nodesFunction.left.at(relation.right);
output << formatCall % (scopeFrom) % (functionTo) << endl;
}
//function specializations descrtiption
//SECTIONTAG late-context cfa_function_specializations
boost::format formatSpecializations("cfa_function_specializations(%1%, %2%).");
const list<ManagedFnPtr>& functions = __clasp->ast->getAllFunctions();
for (auto f: functions){
if (f->guardContext.isValid()){
list<string> guardRaw = xreate::analysis::compile(f->guardContext);
assert(guardRaw.size() == 1);
output << formatSpecializations % (f->getName()) % (guardRaw.front()) << endl;
}
}
+
+ //Dependencies
+ boost::format formatDependencies("cfa_scope_depends(%1%, %2%).");
+ for(const auto relation: __dependencyRelations){
+ output << formatDependencies % relation.first % relation.second << endl;
+ }
+ std::multimap<ScopePacked, ScopePacked> __dependencyRelations;
}
void
CFAGraph::addFunctionAnnotations(const std::string& function, const std::map<std::string, Expression>& tags) {
unsigned int fid = registerNodeFunction(function);
for (auto& tag: tags){
__functionTags.emplace(fid, tag.second);
}
}
void
CFAGraph::addScopeAnnotations(const ScopePacked& scope, const std::vector<Expression>& tags){
for (Expression tag: tags){
__scopeTags.emplace(scope, tag);
}
}
void
CFAGraph::addContextRules(const ScopePacked& scope, const std::vector<Expression>& rules){
for (Expression rule: rules){
__contextRules.emplace(scope, rule);
}
}
void
CFAGraph::addCallConnection(const ScopePacked& scopeFrom, const std::string& functionTo) {
unsigned int idFuncTo = registerNodeFunction(functionTo);
__callRelations.insert(CALL_RELATIONS::value_type(scopeFrom, idFuncTo));
}
void
CFAGraph::addParentConnection(const ScopePacked& scope, const std::string& functionParent){
__parentFunctionRelations.insert(PARENT_FUNCTION_RELATIONS::value_type(scope, registerNodeFunction(functionParent)));
}
void
CFAGraph::addParentConnection(const ScopePacked& scope, const ScopePacked& scopeParent){
__parentScopeRelations.emplace(scope, scopeParent);
}
unsigned int
CFAGraph::registerNodeFunction(const std::string& fname){
auto pos = __nodesFunction.left.insert(make_pair(__nodesFunction.size(), fname));
return pos.first->first;
}
+
+void
+CFAGraph::addDependency(const ScopePacked& scope, const ScopePacked& scopeDependency){
+ __dependencyRelations.emplace(scope, scopeDependency);
+}
+
+bool CFAGraph::isDependent(const ScopePacked& scope) const{
+ return __dependencyRelations.count(scope) > 0;
+}
+
+void CFAGraph::transmitDependencies(const ScopePacked& scopeTo, const ScopePacked& scopeFrom){
+ auto range = __dependencyRelations.equal_range(scopeFrom);
+
+ std::list<ScopePacked> dependencies;
+ for (auto pairI = range.first; pairI != range.second; ++pairI){
+ dependencies.push_back(pairI->second);
+ }
+
+ for(auto dep: dependencies){
+ __dependencyRelations.emplace(scopeTo, dep);
+ }
+}
diff --git a/cpp/src/analysis/cfagraph.h b/cpp/src/analysis/cfagraph.h
index 49c66d6..7d97e16 100644
--- a/cpp/src/analysis/cfagraph.h
+++ b/cpp/src/analysis/cfagraph.h
@@ -1,60 +1,63 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* File: CFAGraph.h
* Author: pgess <v.melnychenko@xreate.org>
*
* Created on June 27, 2016, 2:09 PM
*/
#ifndef CFAGRAPH_H
#define CFAGRAPH_H
#include "clasplayer.h"
namespace xreate {namespace cfa {
/** \brief Represents CFA analysis data produced by CFAPass */
class CFAGraph: public IAnalysisReport {
public:
typedef boost::bimap<ScopePacked, boost::bimaps::multiset_of<unsigned int>> PARENT_FUNCTION_RELATIONS;
PARENT_FUNCTION_RELATIONS __parentFunctionRelations;
std::map<ScopePacked, ScopePacked> __parentScopeRelations;
+ std::multimap<ScopePacked, ScopePacked> __dependencyRelations;
typedef boost::bimap<
boost::bimaps::multiset_of<ScopePacked>,
boost::bimaps::multiset_of<unsigned int>,
boost::bimaps::set_of_relation<>
> CALL_RELATIONS;
CALL_RELATIONS __callRelations;
boost::bimap<unsigned int, std::string > __nodesFunction;
std::multimap<unsigned int, Expression> __functionTags;
std::multimap<ScopePacked, Expression> __scopeTags;
std::multimap<ScopePacked, ContextRule> __contextRules;
void print(std::ostringstream& output) const override;
CFAGraph(ClaspLayer* engine): __clasp(engine){}
void addFunctionAnnotations(const std::string& function, const std::map<std::string, Expression>& tags);
void addScopeAnnotations(const ScopePacked& scope, const std::vector<Expression>&tags);
void addContextRules(const ScopePacked& scope, const std::vector<Expression>&rules);
void addCallConnection(const ScopePacked& scopeFrom, const std::string& functionTo);
void addParentConnection(const ScopePacked& scope, const std::string& functionParent);
void addParentConnection(const ScopePacked& scope, const ScopePacked& scopeParent);
- // void addScopeRetIdentifier(const ScopePacked& scope, const SymbolPacked& identifier);
+ void addDependency(const ScopePacked& scope, const ScopePacked& scopeDependency);
+ bool isDependent(const ScopePacked& scope) const;
+ void transmitDependencies(const ScopePacked& scopeTo, const ScopePacked& scopeFrom);
private:
ClaspLayer* __clasp;
unsigned int registerNodeFunction(const std::string& fname);
};
}} //end of namespace xreate::cfa
#endif /* CFAGRAPH_H */
diff --git a/cpp/src/clasplayer.h b/cpp/src/clasplayer.h
index 2e4157a..1ad660e 100644
--- a/cpp/src/clasplayer.h
+++ b/cpp/src/clasplayer.h
@@ -1,229 +1,231 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* Author: pgess <v.melnychenko@xreate.org>
* File: clasplayer.h
*/
#ifndef CLASPLAYER_H
#define CLASPLAYER_H
#include "ast.h"
#include "contextrule.h"
#include <clingo/clingocontrol.hh>
#include <string>
#include <climits>
#include <boost/bimap.hpp>
#include <boost/bimap/multiset_of.hpp>
#include <boost/optional.hpp>
#include <boost/scoped_ptr.hpp>
#include <list>
+#include <limits>
namespace xreate {
typedef unsigned int ScopePacked;
+const ScopePacked SCOPE_ABSTRACT_GLOBAL = std::numeric_limits<ScopePacked>::max();
struct SymbolPacked {
SymbolPacked(){}
SymbolPacked(ScopedSymbol i, ScopePacked s): identifier(i.id), version(i.version), scope(s){}
SymbolPacked(VNameId symbolId, versions::VariableVersion symbolVersion, ScopePacked symbolScope)
: identifier(symbolId), version(symbolVersion), scope(symbolScope){}
VNameId identifier;
versions::VariableVersion version;
ScopePacked scope;
};
bool operator==(const SymbolPacked& s1, const SymbolPacked& s2);
bool operator<(const SymbolPacked& s1, const SymbolPacked& s2);
enum class DFGConnection {
STRONG, WEAK, PROTOTYPE
};
/** \brief Designated to mark analysis results that can be composed as *logic program* */
class IAnalysisReport {
public:
/** \brief Composes *logic program* based on analysis data into ASP format and appends to a stream*/
virtual void print(std::ostringstream& output) const = 0;
virtual ~IAnalysisReport(){};
};
/** \brief Logic program query interface */
class IQuery {
public:
virtual void init(ClaspLayer* clasp) = 0;
virtual ~IQuery() {}
};
enum class QueryId {
ContainersQuery,
ContextQuery,
PtrvalidQuery,
PolymorphQuery
};
namespace dfa{
class DFAGraph;
}
namespace cfa {
class CFAGraph;
}
class ClaspLayer {
friend class ContextRule;
/**\name Data Providers Management */
///@{
public:
void registerReport(IAnalysisReport* report);
void runReports();
/** \brief Appends arbitrary string to *logic program*
*/
void addRawScript(std::string&& script);
private:
std::list<IAnalysisReport*> __reports;
/** Includes external text files to a *logic program* */
void involveImports();
///@}
/**\name Queries Management */
///@{
public:
/** \brief Adds query. See xreate::IQuery */
IQuery* registerQuery(IQuery* query, const QueryId& id);
/** \brief Returns particular query. See xreate::IQuery */
IQuery* getQuery(const QueryId& id);
template<class ...Types>
static std::tuple<Types...> parse(const Gringo::Symbol& atom);
typedef std::multimap<std::string, Gringo::Symbol>::const_iterator ModelIterator;
typedef boost::optional<std::pair<ClaspLayer::ModelIterator, ClaspLayer::ModelIterator>> ModelFragment;
ModelFragment query(const std::string& atom);
size_t getScopesCount() const;
SymbolPacked pack(const Symbol& symbol, std::string hintSymbolName = "");
ScopePacked pack(const CodeScope * const scope);
Symbol unpack(const SymbolPacked& symbol);
std::string getHintForPackedSymbol(const SymbolPacked& symbol);
///@}
private:
std::map<QueryId, IQuery*> __queries;
std::multimap<std::string, Gringo::Symbol> __model;
std::map<SymbolPacked, std::string> __indexSymbolNameHints;
std::unordered_map<const CodeScope*, unsigned int> __indexScopes;
std::vector<const CodeScope*> __registryScopes;
/**\name Diagnostic */
///@{
//TODO diagnostic move over to separate provider/query
public:
/** \brief Adds diagnostic rule */
void addRuleWarning(const RuleWarning &rule);
/** \brief Registers diagnostic messages */
unsigned int registerWarning(std::string &&message);
private:
std::map<unsigned int, std::string> __warnings;
void printWarnings(std::ostream& out);
///@}
///@{
public:
ClaspLayer();
/** \brief Executes reasoning */
void run();
///@}
AST *ast;
private:
std::ostringstream __partTags;
std::ostringstream __partGeneral;
bool handleSolution(Gringo::Model const &model);
};
template<class typ>
struct ParseImplAtom {
static typ get(const Gringo::Symbol& atom) {
return atom.num();
}
};
template<>
struct ParseImplAtom<int> {
static int get(const Gringo::Symbol& atom);
};
template<>
struct ParseImplAtom<std::string> {
static std::string get(const Gringo::Symbol& atom);
};
template<>
struct ParseImplAtom<SymbolPacked> {
static SymbolPacked get(const Gringo::Symbol& atom);
};
template<>
struct ParseImplAtom<Gringo::Symbol> {
static Gringo::Symbol get(const Gringo::Symbol& atom);
};
template<>
struct ParseImplAtom<std::list<Gringo::Symbol>>{
static std::list<Gringo::Symbol> get(const Gringo::Symbol& atom);
};
template<>
struct ParseImplAtom<Expression> {
static Expression get(const Gringo::Symbol& atom);
};
template<class Tuple, size_t index>
struct Parse_Impl {
static void parse(Tuple& tup, Gringo::SymSpan::iterator arg) {
const size_t tupleSize = std::tuple_size<Tuple>::value;
typedef typename std::tuple_element < tupleSize - index, Tuple>::type ElType;
ElType& el = std::get < tupleSize - index > (tup);
Gringo::Symbol atom = *arg;
el = ParseImplAtom<ElType>::get(atom);
Parse_Impl<Tuple, index - 1 > ::parse(tup, ++arg);
}
};
template<class Tuple>
struct Parse_Impl<Tuple, 0> {
static void parse(Tuple& tup, Gringo::SymSpan::iterator arg) {
}
};
template<class ...Types>
std::tuple<Types...>
ClaspLayer::parse(const Gringo::Symbol& atom) {
typedef std::tuple < Types...> Tuple;
Tuple tup;
Parse_Impl<Tuple, std::tuple_size<Tuple>::value>::parse(tup, atom.args().first);
return tup;
}
} //end of xreate namespace
#endif
diff --git a/cpp/src/pass/abstractpass.h b/cpp/src/pass/abstractpass.h
index a91d829..d09f83b 100644
--- a/cpp/src/pass/abstractpass.h
+++ b/cpp/src/pass/abstractpass.h
@@ -1,206 +1,207 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* Author: pgess <v.melnychenko@xreate.org>
*/
#ifndef ABSTRACTPASS_H
#define ABSTRACTPASS_H
#include "ast.h"
#include "xreatemanager.h"
#include<iostream>
namespace xreate
{
/** \brief Holds current position in %AST while traversing*/
struct PassContext
{
const CodeScope* scope = 0;
ManagedFnPtr function;
ManagedRulePtr rule;
std::string varDecl;
PassContext()
{}
PassContext updateScope(const CodeScope* scopeNew) {
PassContext context2{*this};
context2.scope = scopeNew;
return context2;
}
~PassContext(){}
};
/** \brief Base class for all passes to inherit */
class IPass {
public:
IPass(PassManager* manager);
+ virtual ~IPass(){}
/** \brief Executes pass */
virtual void run()=0;
/** \brief Finalizes pass. Empty by default*/
virtual void finish();
PassManager* man;
};
template<class Output>
Output defaultValue();
template<>
void defaultValue<void>();
/** \brief Stores processing results for already visited nodes */
template<class Output>
class SymbolCache: private std::map<Symbol, Output>{
public:
bool isCached(const Symbol& symbol){
return this->count(symbol);
}
Output setCachedValue(const Symbol& symbol, Output&& value){
(*this)[symbol] = value;
return value;
}
Output getCachedValue(const Symbol& symbol){
assert(this->count(symbol));
return this->at(symbol);
}
};
/** \brief Set of already visited nodes */
template<>
class SymbolCache<void>: private std::set<Symbol>{
public:
bool isCached(const Symbol& symbol){
bool result = this->count(symbol) > 0;
return result;
}
void setCachedValue(const Symbol& symbol){
this->insert(symbol);
}
void getCachedValue(const Symbol& symbol){
}
};
/** \brief Minimal useful IPass implementation*/
template<class Output>
class AbstractPass: public IPass {
SymbolCache<Output> __visitedSymbols;
protected:
virtual Output processSymbol(const Symbol& symbol, PassContext context, const std::string& hintSymbol=""){
if (__visitedSymbols.isCached(symbol))
return __visitedSymbols.getCachedValue(symbol);
const Expression& declaration = CodeScope::getDefinition(symbol, true);
if (declaration.isDefined()){
PassContext context2 = context.updateScope(symbol.scope);
Output&& result = process(declaration, context2, hintSymbol);
return __visitedSymbols.setCachedValue(symbol, std::move(result));
}
return defaultValue<Output>();
}
Output processExpressionCall(const Expression& expression, PassContext context){
const std::string &calleeName = expression.getValueString();
std::list<ManagedFnPtr> callees = man->root->getFunctionSpecializations(calleeName);
if (callees.size() == 1 && callees.front()){
return processFnCall(callees.front(), context);
} else {
for (const ManagedFnPtr& callee: callees){
processFnCallUncertain(callee, context);
}
return defaultValue<Output>();
}
}
SymbolCache<Output>& getSymbolCache(){
return __visitedSymbols;
}
public:
AbstractPass(PassManager* manager)
: IPass(manager){}
/** \brief Processes function invocation instruction */
virtual Output processFnCall(ManagedFnPtr functionCallee, PassContext context){
return defaultValue<Output>();
}
/** \brief Processes function invocation instruction in uncertain cases
* \details Executed when it's impossible statically determine exact function invocation.
* In this case get executed for all possible candidates
*/
virtual void processFnCallUncertain(ManagedFnPtr functionCallee, PassContext context)
{}
/** \brief Processes Logic Rule */
virtual void process(ManagedRulePtr rule)
{}
/** \brief Processes Function */
virtual Output process(ManagedFnPtr function)
{
PassContext context;
context.function = function;
return process(function->getEntryScope(), context);
}
/** \brief Processes single CodeScope */
virtual Output process(CodeScope* scope, PassContext context, const std::string& hintBlockDecl=""){
context.scope = scope;
return processSymbol(Symbol{ScopedSymbol::RetSymbol, scope}, context);
}
//TODO expose Symbol instead of varDecl. Required by DFAPass.
/** \brief Processes single Expression */
virtual Output process(const Expression& expression, PassContext context, const std::string& varDecl=""){
if (expression.__state == Expression::IDENT){
assert(context.scope);
return processSymbol(Attachments::get<IdentifierSymbol>(expression), context, expression.getValueString());
}
assert(false);
return defaultValue<Output>();
}
/** \brief Executes AST traverse */
void run() {
ManagedRulePtr rule = man->root->begin<MetaRuleAbstract>();
while (rule.isValid()) {
process(rule);
++rule;
}
ManagedFnPtr f = man->root->begin<Function>();
while (f.isValid()) {
process(f);
++f;
}
}
};
template<>
void
AbstractPass<void>::processSymbol(const Symbol& symbol, PassContext context, const std::string& hintSymbol);
template<>
void
AbstractPass<void>::process(const Expression& expression, PassContext context, const std::string& hintSymbol);
}
#endif
diff --git a/cpp/src/pass/cfapass.cpp b/cpp/src/pass/cfapass.cpp
index a317acd..e4fdcb4 100644
--- a/cpp/src/pass/cfapass.cpp
+++ b/cpp/src/pass/cfapass.cpp
@@ -1,124 +1,196 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* cfapass.cpp
*
* Author: pgess <v.melnychenko@xreate.org>
*/
/**
* \file cfapass.h
* \brief Control Flow Analysis(CFA)
*/
#include "cfapass.h"
#include "analysis/cfagraph.h"
#include "analysis/DominatorsTreeAnalysisProvider.h"
#include <boost/range/iterator_range_core.hpp>
using namespace std;
using namespace xreate::cfa;
void
-CFAPass::initSignatures(){
+CFAPassBasic::initSignatures(){
auto range = man->root->__interfacesData.equal_range(CFA);
for (auto i = range.first; i!= range.second; ++i){
__signatures.emplace(i->second.op, i->second);
}
}
-void CFAPass::run(){
+void
+CFAPassBasic::run(){
initSignatures();
return AbstractPass::run();
}
void
-CFAPass::finish()
-{
+CFAPassBasic::finish(){
man->clasp->registerReport(__context.graph);
dominators::DominatorsTreeAnalysisProvider* reportDominators = new dominators::DominatorsTreeAnalysisProvider();
- reportDominators->run(man->clasp, __context.graph);
+ reportDominators->run(__context.graph);
man->clasp->registerReport(reportDominators);
return AbstractPass::finish();
}
void
-CFAPass::processFnCall(ManagedFnPtr function, PassContext context)
-{
+CFAPassBasic::processFnCall(ManagedFnPtr function, PassContext context){
ClaspLayer* clasp = man->clasp;
__context.graph->addCallConnection(clasp->pack(context.scope), function->getName());
return AbstractPass::processFnCall(function, context);
}
void
-CFAPass::processFnCallUncertain(ManagedFnPtr function, PassContext context){
+CFAPassBasic::processFnCallUncertain(ManagedFnPtr function, PassContext context){
ClaspLayer* clasp = man->clasp;
__context.graph->addCallConnection(clasp->pack(context.scope), function->getName());
return AbstractPass::processFnCallUncertain(function, context);
}
void
-CFAPass::process(CodeScope* scope, PassContext context, const std::string& hintBlockDecl){
+CFAPassBasic::process(CodeScope* scope, PassContext context, const std::string& hintBlockDecl){
ClaspLayer* clasp = man->clasp;
const CodeScope* scopeParent = context.scope;
ScopePacked scopeId = clasp->pack(scope);
+ //Parent Relations
if (scopeParent){
- __context.graph->addParentConnection(scopeId, clasp->pack(scopeParent));
+ __context.graph->addParentConnection(scopeId, clasp->pack(scopeParent));
} else {
- __context.graph->addParentConnection(scopeId, context.function->getName());
+ __context.graph->addParentConnection(scopeId, context.function->getName());
}
- //TOTEST scope annotations
- //SECTIONTAG context gather scope annotations
+ //TOTEST scope annotations
+ //SECTIONTAG context gather scope annotations
__context.graph->addScopeAnnotations(scopeId, scope->tags);
__context.graph->addContextRules(scopeId, scope->contextRules);
return AbstractPass::process(scope, context, hintBlockDecl);
}
//TOTEST scope annotations via scheme
void
-CFAPass::process(const Expression& expression, PassContext context, const std::string& varDecl){
+CFAPassBasic::process(const Expression& expression, PassContext context, const std::string& varDecl){
ClaspLayer* clasp = man->clasp;
if (expression.__state == Expression::COMPOUND){
Operator op= expression.op;
if (__signatures.count(op)) {
assert(expression.blocks.size());
for (const auto& scheme: boost::make_iterator_range(__signatures.equal_range(expression.op))) {
__context.graph->addScopeAnnotations(clasp->pack(expression.blocks.front()), scheme.second.getOperands());
}
}
}
return AbstractPass::process(expression, context, varDecl);
}
void
-CFAPass::process(ManagedFnPtr function)
-{
+CFAPassBasic::process(ManagedFnPtr function){
__context.graph->addFunctionAnnotations(function->getName(), function->getTags());
return AbstractPass::process(function);
}
-CFAPass::CFAPass(PassManager* manager)
- : AbstractPass(manager)
+CFAPassBasic::CFAPassBasic(PassManager* manager)
+: AbstractPass(manager)
, __context{new CFAGraph(manager->clasp)}
{}
+/****************************SCOPE DEPENDENCIES********************************/
+void
+CFAPassDependenciesDecorator::process(const Expression& expression, PassContext context, const std::string& varDecl){
+ ClaspLayer* clasp = man->clasp;
+
+ if (expression.__state == Expression::COMPOUND)
+ switch(expression.op){
+ case Operator::SEQUENCE:{
+ ScopePacked scopePrev = clasp->pack(expression.blocks.front());
+ for(auto scopeIt= ++expression.blocks.begin(); scopeIt != expression.blocks.end(); ++scopeIt){
+ ScopePacked scopeCurrent = clasp->pack(*scopeIt);
+ __context.graph->addDependency(scopeCurrent, scopePrev);
+ scopePrev = scopeCurrent;
+ }
+ break;
+ }
+
+ default: break;
+ }
+
+ return Parent::process(expression, context, varDecl);
+}
+
+void
+CFAPassDependenciesDecorator::processFnCall(ManagedFnPtr function, PassContext context){
+ ClaspLayer* clasp = man->clasp;
+
+ const CodeScope* scopeCaller = context.scope;
+ assert(scopeCaller);
+ ScopePacked scopeCallerPacked = clasp->pack(scopeCaller);
+
+ if(__context.graph->isDependent(scopeCallerPacked)){
+ ScopePacked scopeCalleePacked = clasp->pack(function->getEntryScope());
+ __context.graph->transmitDependencies(scopeCalleePacked, scopeCallerPacked);
+ }
+
+ Parent::processFnCall(function, context);
+}
+
+void
+CFAPassDependenciesDecorator::processFnCallUncertain(ManagedFnPtr function, PassContext context){
+ ClaspLayer* clasp = man->clasp;
+
+ const CodeScope* scopeCaller = context.scope;
+ assert(scopeCaller);
+ ScopePacked scopeCallerPacked = clasp->pack(scopeCaller);
+
+ if(__context.graph->isDependent(scopeCallerPacked)){
+ ScopePacked scopeCalleePacked = clasp->pack(function->getEntryScope());
+ __context.graph->transmitDependencies(scopeCalleePacked, scopeCallerPacked);
+ }
+
+ Parent::processFnCallUncertain(function, context);
+}
+
+void
+CFAPassDependenciesDecorator::process(CodeScope* scope,
+ PassContext context, const std::string& hintBlockDecl){
+
+ ClaspLayer* clasp = man->clasp;
+ const CodeScope* scopeParent = context.scope;
+
+ if (scopeParent){
+ ScopePacked scopePacked = clasp->pack(scope);
+ ScopePacked scopeParentPacked = clasp->pack(scopeParent);
+ if (!__context.graph->isDependent(scopePacked) &&
+ __context.graph->isDependent(scopeParentPacked)) {
+ __context.graph->transmitDependencies(scopePacked, scopeParentPacked);
+ }
+ }
+
+ Parent::process(scope, context, hintBlockDecl);
+}
/**
* \class xreate::cfa::CFAPass
* \details Provides CFA, important analysis for reasoning. Iterates over AST and stores collected data in CFAGraph
*/
\ No newline at end of file
diff --git a/cpp/src/pass/cfapass.h b/cpp/src/pass/cfapass.h
index 7e12062..6351126 100644
--- a/cpp/src/pass/cfapass.h
+++ b/cpp/src/pass/cfapass.h
@@ -1,49 +1,67 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* Author: pgess <v.melnychenko@xreate.org>
*
* cfapass.cpp
* Control Flow Graph building pass
*/
#ifndef CFGPASS_H
#define CFGPASS_H
#include "xreatemanager.h"
#include "clasplayer.h"
#include "abstractpass.h"
namespace xreate{namespace cfa {
class CFAGraph;
/** \brief Control Flow Analysis Pass(%CFA)*/
-class CFAPass : public AbstractPass<void>
-{
+class CFAPassBasic : public AbstractPass<void>{
public:
void process(ManagedFnPtr function) override;
void processFnCall(ManagedFnPtr function, PassContext context) override;
void processFnCallUncertain(ManagedFnPtr function, PassContext context) override;
void process(CodeScope* scope, PassContext context, const std::string& hintBlockDecl="") override;
void process(const Expression& expression, PassContext context, const std::string& varDecl="") override;
- CFAPass(PassManager* manager);
-
+ CFAPassBasic(PassManager* manager);
void finish() override;
void run() override;
-private:
+
+ const CFAGraph* getReport() const {return __context.graph; }
+
+protected:
struct {
CFAGraph* graph;
} __context;
std::multimap<Operator, Expression> __signatures; //CFA data for particular operators
void initSignatures();
};
+class CFAPassDependenciesDecorator: public CFAPassBasic{
+ typedef CFAPassBasic Parent;
+
+public:
+ CFAPassDependenciesDecorator(PassManager* manager): CFAPassBasic(manager) {}
+
+ void process(const Expression& expression, PassContext context, const std::string& varDecl) override;
+ void processFnCall(ManagedFnPtr function, PassContext context) override;
+ void processFnCallUncertain(ManagedFnPtr function, PassContext context) override;
+ void process(CodeScope* scope, PassContext context, const std::string& hintBlockDecl) override;
+};
+
+class CFAPass: public CFAPassDependenciesDecorator{
+public:
+ CFAPass(PassManager* manager): CFAPassDependenciesDecorator(manager) {}
+};
+
}} //end of namespace xreate::cfa
#endif // CFGPASS_H
diff --git a/cpp/tests/cfa.cpp b/cpp/tests/cfa.cpp
index 65ee929..0f8075e 100644
--- a/cpp/tests/cfa.cpp
+++ b/cpp/tests/cfa.cpp
@@ -1,122 +1,197 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*
* testsCFG.cpp
*
* Created on: Jul 17, 2015
* Author: pgess <v.melnychenko@xreate.org>
*/
#include "xreatemanager.h"
#include "pass/dfapass.h"
#include "pass/cfapass.h"
#include "analysis/DominatorsTreeAnalysisProvider.h"
#include "gtest/gtest.h"
+#include "analysis/cfagraph.h"
#include <boost/scoped_ptr.hpp>
#include <boost/smart_ptr/scoped_array.hpp>
using namespace xreate;
using namespace xreate::cfa;
using namespace std;
TEST(CFA, testFunctionAnnotationsClasp){
string&& program =
"f2 = function::int; annotationF2 {\n"
" 0\n"
"}\n"
"\n"
"f1 = function:: int; entry; annotationF1 {\n"
" f2() + 10\n"
"}";
details::tier1::XreateManager* man = details::tier1::XreateManager::prepare(move(program));
man->analyse();
ClaspLayer::ModelFragment answer = man->clasp->query("annotationF1");
int countNoneValue = 0;
if (answer) countNoneValue = std::distance(answer->first, answer->second);
EXPECT_EQ(1, countNoneValue);
answer = man->clasp->query("annotationF2");
countNoneValue = 0;
if (answer) countNoneValue = std::distance(answer->first, answer->second);
EXPECT_EQ(1, countNoneValue);
}
TEST(CFA, testLoopContextExists){
details::tier1::XreateManager* man = details::tier1::XreateManager::prepare (
"interface(cfa){\n"
" operator fold:: annotation1.\n"
"}\n"
"\n"
"main = function:: int; entry {\n"
" x = [1..10]:: [int].\n"
" sum = loop fold (x->el:: int, 0->sum):: int {\n"
" el + sum + f1()\n"
" }. \n"
" sum\n"
"}"
"case context:: annotation1 {"
" f1 = function::int {\n"
" x = 0:: int. "
" x\n"
" }"
"}"
);
man->analyse();
ClaspLayer::ModelFragment model = man->clasp->query("annotation1");
ScopePacked scopeIdActual = std::get<0>(ClaspLayer::parse<ScopePacked>(model->first->second));
CodeScope* scopeEntry = man->root->findFunction("main")->getEntryScope();
const Expression& exprSum = scopeEntry->getDefinition(scopeEntry->getSymbol("sum"));
CodeScope* scopeExpected = exprSum.blocks.front();
ScopePacked scopeIdExpected = man->clasp->pack(scopeExpected);
ASSERT_EQ(scopeIdExpected, scopeIdActual);
}
-TEST(CFA, CFGRoots){
+TEST(CFA, DependenciesFnCall){
+ details::tier2::XreateManager* man = details::tier2::XreateManager::prepare(
+ R"Code(
+ a = function::int{
+ seq
+ {x = 0:: int. x}
+ {x = b():: int. x}::int
+ }
+
+ b = function::int {y = 0. y}
+ )Code");
+
+ CodeScope* scopeSeq1 = man->root->findFunction("a")->getEntryScope()->getBody().blocks.front();
+ CodeScope* scopeSeq2 = *(++man->root->findFunction("a")->getEntryScope()->getBody().blocks.begin());
+ CodeScope* scopeB = man->root->findFunction("b")->getEntryScope();
+
+ ScopePacked psSeq1 = man->clasp->pack(scopeSeq1);
+ ScopePacked psSeq2 = man->clasp->pack(scopeSeq2);
+ ScopePacked psB = man->clasp->pack(scopeB);
+
+ CFAPass* pass = new CFAPass(man);
+
+ man->registerPass(pass, PassId::CFGPass);
+ man->executePasses();
+ const CFAGraph* report = dynamic_cast<CFAPassBasic*>(man->getPassById(PassId::CFGPass))->getReport();
+ auto dependencies = report->__dependencyRelations;
+ delete pass;
+
+ ASSERT_EQ(1, dependencies.count(psSeq2));
+ ASSERT_EQ(1, dependencies.count(psB));
+}
+
+TEST(CFA, DependenciesChildScope){
+ details::tier2::XreateManager* man = details::tier2::XreateManager::prepare(
+ R"Code(
+ a = function::int{
+ seq
+ {x = 0:: int. x}
+ {x=0::int. if(x>0)::int{1} else {0}}::int
+ }
+ )Code");
+
+ CodeScope* scopeSeq1 = man->root->findFunction("a")->getEntryScope()->getBody().blocks.front();
+ CodeScope* scopeSeq2 = *(++man->root->findFunction("a")->getEntryScope()->getBody().blocks.begin());
+ CodeScope* scopeIf1 = scopeSeq2->getBody().blocks.front();
+ CodeScope* scopeIf2 = *(++scopeSeq2->getBody().blocks.begin());
+
+ ScopePacked psSeq1 = man->clasp->pack(scopeSeq1);
+ ScopePacked psSeq2 = man->clasp->pack(scopeSeq2);
+ ScopePacked psIf1 = man->clasp->pack(scopeIf1);
+ ScopePacked psIf2 = man->clasp->pack(scopeIf2);
+
+ CFAPass* pass = new CFAPass(man);
+
+ man->registerPass(pass, PassId::CFGPass);
+ man->executePasses();
+ const CFAGraph* report = dynamic_cast<CFAPassBasic*>(man->getPassById(PassId::CFGPass))->getReport();
+ auto dependencies = report->__dependencyRelations;
+ delete pass;
+
+ ASSERT_EQ(0, dependencies.count(psSeq1));
+ ASSERT_EQ(1, dependencies.count(psSeq2));
+ ASSERT_EQ(1, dependencies.count(psIf1));
+ ASSERT_EQ(1, dependencies.count(psIf2));
+
+ for(auto rec: dependencies)
+ {
+ std::cout << rec.first << " " << rec.second << std::endl;
+ }
+}
+
+
+TEST(CFA, DomReportOneRoot){
std::string program =
R"CODE(
- main = function::int{a()+ b()}
- a= function::int {c1() + c2()}
- b= function::int {c2()}
- c1=function::int{0}
- c2=function::int{0}
+ a = function:: int; entry{
+ seq
+ {x = 0:: int. x}
+ {x = 1:: int. x}::int
+ }
)CODE";
- std::unique_ptr<details::tier1::XreateManager> man(details::tier1::XreateManager::prepare(move(program)));
- man->analyse();
+ std::unique_ptr<details::tier2::XreateManager> man(details::tier2::XreateManager::prepare(move(program)));
+
+ CFAPass* pass = new CFAPass(man.get());
+ man->registerPass(pass, PassId::CFGPass);
+ pass->run();
+
+ ScopePacked scope1 = man->clasp->pack(man->root->findFunction("a")->getEntryScope()->getBody().blocks.front());
+ ScopePacked scope2 = man->clasp->pack(*++man->root->findFunction("a")->getEntryScope()->getBody().blocks.begin());
+
+ dominators::DominatorsTreeAnalysisProvider* providerDomAnalysis = new dominators::DominatorsTreeAnalysisProvider();
+ providerDomAnalysis->run(pass->getReport());
+
+ dominators::DominatorsTreeAnalysisProvider::Dominators expectedFDom= {
+ {1, {0, 3}}
+ ,{2, {1, 2}}
+ };
+
+ dominators::DominatorsTreeAnalysisProvider::Dominators expectedPostDom= {
+ {2, {0, 3}}
+ ,{1, {1, 2}}
+ };
+
+ auto actualFDom = providerDomAnalysis->getForwardDominators();
+ auto actualPostDom = providerDomAnalysis->getPostDominators();
+
+ ASSERT_EQ(expectedFDom, actualFDom);
+ ASSERT_EQ(expectedPostDom, actualPostDom);
-// manager->registerPass(new CFAPass(manager.get()) , PassId::CFGPass);
-// manager->executePasses();
-// manager->clasp->run();
-//
-// dominators::DominatorsTreeAnalysisProvider domProvider;
-// domProvider.run(manager->clasp);
-//
-// dominators::DominatorsTreeAnalysisProvider::Dominators expectedFDom= {
-// {0, {0, 9}}
-// ,{1, {1, 4}}
-// ,{2, {7, 8}}
-// ,{3, {2, 3}}
-// ,{4, {5, 6}}
-// };
-//
-// dominators::DominatorsTreeAnalysisProvider::Dominators expectedPostDom= {
-// {0, {5, 6}}
-// ,{1, {3, 4}}
-// ,{2, {8, 9}}
-// ,{3, {1, 2}}
-// ,{4, {7, 10}}
-// };
-//
-// ASSERT_EQ(expectedFDom, domProvider.getForwardDominators());
-// ASSERT_EQ(expectedPostDom, domProvider.getPostDominators());
+ delete providerDomAnalysis;
+ delete pass;
}
Event Timeline
Log In to Comment