diff --git a/src/AstToRamTranslator.cpp b/src/AstToRamTranslator.cpp index 13e98528ba5..cefe468b39a 100644 --- a/src/AstToRamTranslator.cpp +++ b/src/AstToRamTranslator.cpp @@ -36,9 +36,11 @@ #include "ast/AstUtils.h" #include "ast/AstVisitor.h" #include "ast/TypeSystem.h" -#include "ast/analysis/AstTypeEnvironmentAnalysis.h" -#include "ast/analysis/AuxArityAnalysis.h" -#include "ast/analysis/PrecedenceGraph.h" +#include "ast/analysis/AstTypeEnvironment.h" +#include "ast/analysis/AuxArity.h" +#include "ast/analysis/RelationSchedule.h" +#include "ast/analysis/SCCGraph.h" +#include "ast/analysis/TopologicallySortedSCCGraph.h" #include "json11.h" #include "ram/RamCondition.h" #include "ram/RamExpression.h" diff --git a/src/FunctorOps.cpp b/src/FunctorOps.cpp index 474d703ff8b..e7e6c08e0c2 100644 --- a/src/FunctorOps.cpp +++ b/src/FunctorOps.cpp @@ -290,4 +290,4 @@ struct FUNCTOR_INTRINSIC_SANCHECKER { } // namespace #endif -} // namespace souffle \ No newline at end of file +} // namespace souffle diff --git a/src/GraphUtils.h b/src/GraphUtils.h index 92718580fcd..cb772e615b3 100644 --- a/src/GraphUtils.h +++ b/src/GraphUtils.h @@ -16,11 +16,13 @@ #pragma once +#include "utility/FileUtil.h" #include #include #include #include #include +#include namespace souffle { @@ -161,4 +163,69 @@ class Graph { } }; +inline std::string toBase64(const std::string& data) { + static const std::vector table = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', + 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', + 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', + 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'}; + std::string result; + std::string tmp = data; + unsigned int padding = 0; + if (data.size() % 3 == 2) { + padding = 1; + } else if (data.size() % 3 == 1) { + padding = 2; + } + + for (unsigned int i = 0; i < padding; i++) { + tmp.push_back(0); + } + for (unsigned int i = 0; i < tmp.size(); i += 3) { + auto c1 = static_cast(tmp[i]); + auto c2 = static_cast(tmp[i + 1]); + auto c3 = static_cast(tmp[i + 2]); + unsigned char index1 = c1 >> 2; + unsigned char index2 = ((c1 & 0x03) << 4) | (c2 >> 4); + unsigned char index3 = ((c2 & 0x0F) << 2) | (c3 >> 6); + unsigned char index4 = c3 & 0x3F; + + result.push_back(table[index1]); + result.push_back(table[index2]); + result.push_back(table[index3]); + result.push_back(table[index4]); + } + if (padding == 1) { + result[result.size() - 1] = '='; + } else if (padding == 2) { + result[result.size() - 1] = '='; + result[result.size() - 2] = '='; + } + return result; +} + +inline std::string convertDotToSVG(const std::string& dotSpec) { + // Check if dot is present + std::string cmd = which("dot"); + if (!isExecutable(cmd)) { + return ""; + } + + TempFileStream dotFile; + dotFile << dotSpec; + dotFile.flush(); + return execStdOut("dot -Tsvg < " + dotFile.getFileName()).str(); +} + +inline void printHTMLGraph(std::ostream& out, const std::string& dotSpec, const std::string& id) { + std::string data = convertDotToSVG(dotSpec); + + if (data.find("
\n"; + } else { + out << "
\n
" << dotSpec << "
\n"; + out << "
\n"; + } +} + } // end of namespace souffle diff --git a/src/Makefile.am b/src/Makefile.am index af9939737b1..91fa6b0e4f3 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -127,21 +127,21 @@ souffle_sources = \ ast/TypeSystem.cpp \ ast/TypeSystem.h \ ast/analysis/AstAnalysis.h \ - ast/analysis/AstConstraintAnalysis.h \ - ast/analysis/AstGroundAnalysis.cpp \ - ast/analysis/AstGroundAnalysis.h \ - ast/analysis/AstIOTypeAnalysis.cpp \ - ast/analysis/AstIOTypeAnalysis.h \ + ast/analysis/AstConstraint.h \ + ast/analysis/AstGround.cpp \ + ast/analysis/AstGround.h \ + ast/analysis/AstIOType.cpp \ + ast/analysis/AstIOType.h \ ast/analysis/AstProfileUse.cpp \ ast/analysis/AstProfileUse.h \ - ast/analysis/AstTypeAnalysis.cpp \ - ast/analysis/AstTypeAnalysis.h \ - ast/analysis/AstTypeEnvironmentAnalysis.cpp \ - ast/analysis/AstTypeEnvironmentAnalysis.h \ - ast/analysis/AuxArityAnalysis.cpp \ - ast/analysis/AuxArityAnalysis.h \ - ast/analysis/ComponentLookupAnalysis.cpp \ - ast/analysis/ComponentLookupAnalysis.h \ + ast/analysis/AstType.cpp \ + ast/analysis/AstType.h \ + ast/analysis/AstTypeEnvironment.cpp \ + ast/analysis/AstTypeEnvironment.h \ + ast/analysis/AuxArity.cpp \ + ast/analysis/AuxArity.h \ + ast/analysis/ComponentLookup.cpp \ + ast/analysis/ComponentLookup.h \ ast/analysis/PrecedenceGraph.cpp \ ast/analysis/PrecedenceGraph.h \ ast/transform/AstComponentChecker.cpp \ diff --git a/src/ast/AstTranslationUnit.h b/src/ast/AstTranslationUnit.h index 8a33a73b7df..1fd1b80995b 100644 --- a/src/ast/AstTranslationUnit.h +++ b/src/ast/AstTranslationUnit.h @@ -22,7 +22,8 @@ #include "Global.h" #include "ast/AstProgram.h" #include "ast/analysis/AstAnalysis.h" -#include "ast/analysis/PrecedenceGraph.h" +#include "ast/analysis/RecursiveClauses.h" +#include "ast/analysis/SCCGraph.h" #include #include #include diff --git a/src/ast/AstUtils.cpp b/src/ast/AstUtils.cpp index 58e05193999..f9f62045138 100644 --- a/src/ast/AstUtils.cpp +++ b/src/ast/AstUtils.cpp @@ -28,7 +28,7 @@ #include "ast/AstRelation.h" #include "ast/AstType.h" #include "ast/AstVisitor.h" -#include "ast/analysis/AstTypeAnalysis.h" +#include "ast/analysis/AstType.h" #include "utility/ContainerUtil.h" #include "utility/MiscUtil.h" #include "utility/StringUtil.h" diff --git a/src/ast/analysis/AstConstraintAnalysis.h b/src/ast/analysis/AstConstraint.h similarity index 99% rename from src/ast/analysis/AstConstraintAnalysis.h rename to src/ast/analysis/AstConstraint.h index 37d40800123..3e500c28c4a 100644 --- a/src/ast/analysis/AstConstraintAnalysis.h +++ b/src/ast/analysis/AstConstraint.h @@ -8,7 +8,7 @@ /************************************************************************ * - * @file AstConstraintAnalysis.h + * @file AstConstraint.h * * Contains AST Constraint Analysis Infrastructure for doing constraint analysis on AST objects * diff --git a/src/ast/analysis/AstGroundAnalysis.cpp b/src/ast/analysis/AstGround.cpp similarity index 97% rename from src/ast/analysis/AstGroundAnalysis.cpp rename to src/ast/analysis/AstGround.cpp index 38774a0d103..26fb6193443 100644 --- a/src/ast/analysis/AstGroundAnalysis.cpp +++ b/src/ast/analysis/AstGround.cpp @@ -14,18 +14,17 @@ * ***********************************************************************/ -#include "ast/analysis/AstGroundAnalysis.h" +#include "ast/analysis/AstGround.h" #include "BinaryConstraintOps.h" #include "Constraints.h" -#include "PrecedenceGraph.h" #include "RelationTag.h" #include "ast/AstArgument.h" #include "ast/AstClause.h" #include "ast/AstLiteral.h" +#include "ast/AstRelation.h" #include "ast/AstTranslationUnit.h" -#include "ast/AstVisitor.h" -#include "ast/analysis/AstConstraintAnalysis.h" -#include "ast/analysis/AstGroundAnalysis.h" +#include "ast/analysis/AstConstraint.h" +#include "ast/analysis/RelationDetailCache.h" #include "utility/StreamUtil.h" #include #include diff --git a/src/ast/analysis/AstGroundAnalysis.h b/src/ast/analysis/AstGround.h similarity index 97% rename from src/ast/analysis/AstGroundAnalysis.h rename to src/ast/analysis/AstGround.h index c93e1e32276..d79ac60b912 100644 --- a/src/ast/analysis/AstGroundAnalysis.h +++ b/src/ast/analysis/AstGround.h @@ -8,7 +8,7 @@ /************************************************************************ * - * @file AstGroundAnalysis.h + * @file AstGround.h * * Defines a function for computing the grounded arguments in a clause * diff --git a/src/ast/analysis/AstIOTypeAnalysis.cpp b/src/ast/analysis/AstIOType.cpp similarity index 97% rename from src/ast/analysis/AstIOTypeAnalysis.cpp rename to src/ast/analysis/AstIOType.cpp index 13e353af5c8..cac34cdcc46 100644 --- a/src/ast/analysis/AstIOTypeAnalysis.cpp +++ b/src/ast/analysis/AstIOType.cpp @@ -14,7 +14,7 @@ * ***********************************************************************/ -#include "ast/analysis/AstIOTypeAnalysis.h" +#include "ast/analysis/AstIOType.h" #include "ast/AstIO.h" #include "ast/AstProgram.h" #include "ast/AstQualifiedName.h" diff --git a/src/ast/analysis/AstIOTypeAnalysis.h b/src/ast/analysis/AstIOType.h similarity index 98% rename from src/ast/analysis/AstIOTypeAnalysis.h rename to src/ast/analysis/AstIOType.h index 9512955c39f..181c947dc83 100644 --- a/src/ast/analysis/AstIOTypeAnalysis.h +++ b/src/ast/analysis/AstIOType.h @@ -8,7 +8,7 @@ /************************************************************************ * - * @file AstIOTypeAnalysis.h + * @file AstIOType.h * * Declares methods to identify a relation as input, output, or printsize. * diff --git a/src/ast/analysis/AstTypeAnalysis.cpp b/src/ast/analysis/AstType.cpp similarity index 99% rename from src/ast/analysis/AstTypeAnalysis.cpp rename to src/ast/analysis/AstType.cpp index 5b8b6491b87..83d323cddbe 100644 --- a/src/ast/analysis/AstTypeAnalysis.cpp +++ b/src/ast/analysis/AstType.cpp @@ -14,12 +14,13 @@ * ***********************************************************************/ -#include "ast/analysis/AstTypeAnalysis.h" +#include "ast/analysis/AstType.h" #include "AggregateOp.h" #include "Constraints.h" #include "FunctorOps.h" #include "Global.h" #include "RamTypes.h" +#include "ast/AstAbstract.h" #include "ast/AstArgument.h" #include "ast/AstAttribute.h" #include "ast/AstClause.h" @@ -32,10 +33,11 @@ #include "ast/AstUtils.h" #include "ast/AstVisitor.h" #include "ast/TypeSystem.h" -#include "ast/analysis/AstConstraintAnalysis.h" -#include "ast/analysis/AstTypeEnvironmentAnalysis.h" +#include "ast/analysis/AstConstraint.h" +#include "ast/analysis/AstTypeEnvironment.h" #include "utility/ContainerUtil.h" #include "utility/FunctionalUtil.h" +#include "utility/MiscUtil.h" #include "utility/StringUtil.h" #include #include diff --git a/src/ast/analysis/AstTypeAnalysis.h b/src/ast/analysis/AstType.h similarity index 98% rename from src/ast/analysis/AstTypeAnalysis.h rename to src/ast/analysis/AstType.h index 064e33b6e9c..3fc0ad9ab30 100644 --- a/src/ast/analysis/AstTypeAnalysis.h +++ b/src/ast/analysis/AstType.h @@ -8,7 +8,7 @@ /************************************************************************ * - * @file AstTypeAnalysis.h + * @file AstType.h * * A collection of type analyses operating on AST constructs. * diff --git a/src/ast/analysis/AstTypeEnvironmentAnalysis.cpp b/src/ast/analysis/AstTypeEnvironment.cpp similarity index 99% rename from src/ast/analysis/AstTypeEnvironmentAnalysis.cpp rename to src/ast/analysis/AstTypeEnvironment.cpp index 1bc2bd9d1c5..b15d0f23669 100644 --- a/src/ast/analysis/AstTypeEnvironmentAnalysis.cpp +++ b/src/ast/analysis/AstTypeEnvironment.cpp @@ -14,7 +14,7 @@ * ***********************************************************************/ -#include "ast/analysis/AstTypeEnvironmentAnalysis.h" +#include "ast/analysis/AstTypeEnvironment.h" #include "GraphUtils.h" #include "ast/AstAttribute.h" #include "ast/AstProgram.h" @@ -23,6 +23,7 @@ #include "ast/TypeSystem.h" #include "utility/MiscUtil.h" #include "utility/tinyformat.h" +#include #include #include #include diff --git a/src/ast/analysis/AstTypeEnvironmentAnalysis.h b/src/ast/analysis/AstTypeEnvironment.h similarity index 97% rename from src/ast/analysis/AstTypeEnvironmentAnalysis.h rename to src/ast/analysis/AstTypeEnvironment.h index 90ac575cab3..ebe2d54c2f4 100644 --- a/src/ast/analysis/AstTypeEnvironmentAnalysis.h +++ b/src/ast/analysis/AstTypeEnvironment.h @@ -8,7 +8,7 @@ /************************************************************************ * - * @file AstTypeEnvironmentAnalysis.h + * @file AstTypeEnvironment.h * * A wrapper for TypeEnvironment to be used for AST Analysis * @@ -26,7 +26,6 @@ #include #include #include -#include namespace souffle { diff --git a/src/ast/analysis/AuxArityAnalysis.cpp b/src/ast/analysis/AuxArity.cpp similarity index 77% rename from src/ast/analysis/AuxArityAnalysis.cpp rename to src/ast/analysis/AuxArity.cpp index 753d269cf0e..71cb7076f2f 100644 --- a/src/ast/analysis/AuxArityAnalysis.cpp +++ b/src/ast/analysis/AuxArity.cpp @@ -14,17 +14,13 @@ * ***********************************************************************/ -#include "AuxArityAnalysis.h" +#include "ast/analysis/AuxArity.h" #include "Global.h" -#include "ast/AstClause.h" -#include "ast/AstUtils.h" -#include #include -#include namespace souffle { -size_t AuxiliaryArity::computeArity(const AstRelation* relation) const { +size_t AuxiliaryArity::computeArity(const AstRelation* /* relation */) const { if (Global::config().has("provenance")) { return 2; } else { diff --git a/src/ast/analysis/AuxArityAnalysis.h b/src/ast/analysis/AuxArity.h similarity index 98% rename from src/ast/analysis/AuxArityAnalysis.h rename to src/ast/analysis/AuxArity.h index 024a895f39a..5058d42ad63 100644 --- a/src/ast/analysis/AuxArityAnalysis.h +++ b/src/ast/analysis/AuxArity.h @@ -8,7 +8,7 @@ /************************************************************************ * - * @file AuxArityAnalysis.h + * @file AuxArity.h * * Define of AST analyses classes * diff --git a/src/ast/analysis/ComponentLookupAnalysis.cpp b/src/ast/analysis/ComponentLookup.cpp similarity index 98% rename from src/ast/analysis/ComponentLookupAnalysis.cpp rename to src/ast/analysis/ComponentLookup.cpp index a7e0b852e52..ce0912d72c5 100644 --- a/src/ast/analysis/ComponentLookupAnalysis.cpp +++ b/src/ast/analysis/ComponentLookup.cpp @@ -14,7 +14,7 @@ * ***********************************************************************/ -#include "ComponentLookupAnalysis.h" +#include "ast/analysis/ComponentLookup.h" #include "ast/AstComponent.h" #include "ast/AstProgram.h" #include "ast/AstTranslationUnit.h" diff --git a/src/ast/analysis/ComponentLookupAnalysis.h b/src/ast/analysis/ComponentLookup.h similarity index 98% rename from src/ast/analysis/ComponentLookupAnalysis.h rename to src/ast/analysis/ComponentLookup.h index ce2aeb1a5ac..617e728029f 100644 --- a/src/ast/analysis/ComponentLookupAnalysis.h +++ b/src/ast/analysis/ComponentLookup.h @@ -8,7 +8,7 @@ /************************************************************************ * - * @file ComponentLookupAnalysis.h + * @file ComponentLookup.h * ***********************************************************************/ diff --git a/src/ast/analysis/PrecedenceGraph.cpp b/src/ast/analysis/PrecedenceGraph.cpp index 07f6caff82a..e328cd154c3 100644 --- a/src/ast/analysis/PrecedenceGraph.cpp +++ b/src/ast/analysis/PrecedenceGraph.cpp @@ -16,96 +16,19 @@ * ***********************************************************************/ -#include "PrecedenceGraph.h" -#include "Global.h" -#include "ast/AstClause.h" -#include "ast/AstLiteral.h" -#include "ast/AstNode.h" +#include "ast/analysis/PrecedenceGraph.h" +#include "GraphUtils.h" #include "ast/AstProgram.h" #include "ast/AstQualifiedName.h" #include "ast/AstRelation.h" #include "ast/AstTranslationUnit.h" #include "ast/AstUtils.h" -#include "ast/AstVisitor.h" -#include "ast/analysis/AstIOTypeAnalysis.h" -#include "utility/FileUtil.h" -#include "utility/StreamUtil.h" -#include -#include -#include #include #include +#include namespace souffle { -namespace { -std::string toBase64(const std::string& data) { - static const std::vector table = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', - 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', - 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', - 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'}; - std::string result; - std::string tmp = data; - unsigned int padding = 0; - if (data.size() % 3 == 2) { - padding = 1; - } else if (data.size() % 3 == 1) { - padding = 2; - } - - for (unsigned int i = 0; i < padding; i++) { - tmp.push_back(0); - } - for (unsigned int i = 0; i < tmp.size(); i += 3) { - auto c1 = static_cast(tmp[i]); - auto c2 = static_cast(tmp[i + 1]); - auto c3 = static_cast(tmp[i + 2]); - unsigned char index1 = c1 >> 2; - unsigned char index2 = ((c1 & 0x03) << 4) | (c2 >> 4); - unsigned char index3 = ((c2 & 0x0F) << 2) | (c3 >> 6); - unsigned char index4 = c3 & 0x3F; - - result.push_back(table[index1]); - result.push_back(table[index2]); - result.push_back(table[index3]); - result.push_back(table[index4]); - } - if (padding == 1) { - result[result.size() - 1] = '='; - } else if (padding == 2) { - result[result.size() - 1] = '='; - result[result.size() - 2] = '='; - } - return result; -} - -std::string convertDotToSVG(const std::string& dotSpec) { - // Check if dot is present - std::string cmd = which("dot"); - if (!isExecutable(cmd)) { - return ""; - } - - TempFileStream dotFile; - dotFile << dotSpec; - dotFile.flush(); - return execStdOut("dot -Tsvg < " + dotFile.getFileName()).str(); -} - -void printHTMLGraph(std::ostream& out, const std::string& dotSpec, const std::string& id) { - std::string data = convertDotToSVG(dotSpec); - - if (data.find("
\n"; - } else { - out << "
\n
" << dotSpec << "
\n"; - out << "
\n"; - } -} - -} // namespace - void PrecedenceGraphAnalysis::run(const AstTranslationUnit& translationUnit) { /* Get relations */ const AstProgram& program = *translationUnit.getProgram(); @@ -148,483 +71,4 @@ void PrecedenceGraphAnalysis::print(std::ostream& os) const { printHTMLGraph(os, ss.str(), getName()); } -void RedundantRelationsAnalysis::run(const AstTranslationUnit& translationUnit) { - precedenceGraph = translationUnit.getAnalysis(); - - std::set work; - std::set notRedundant; - auto* ioType = translationUnit.getAnalysis(); - - const std::vector& relations = translationUnit.getProgram()->getRelations(); - /* Add all output relations to the work set */ - for (const AstRelation* r : relations) { - if (ioType->isOutput(r)) { - work.insert(r); - } - } - - /* Find all relations which are not redundant for the computations of the - output relations. */ - while (!work.empty()) { - /* Chose one element in the work set and add it to notRedundant */ - const AstRelation* u = *(work.begin()); - work.erase(work.begin()); - notRedundant.insert(u); - - /* Find all predecessors of u and add them to the worklist - if they are not in the set notRedundant */ - for (const AstRelation* predecessor : precedenceGraph->graph().predecessors(u)) { - if (notRedundant.count(predecessor) == 0u) { - work.insert(predecessor); - } - } - } - - /* All remaining relations are redundant. */ - redundantRelations.clear(); - for (const AstRelation* r : relations) { - if (notRedundant.count(r) == 0u) { - redundantRelations.insert(r); - } - } -} - -void RedundantRelationsAnalysis::print(std::ostream& os) const { - os << redundantRelations << std::endl; -} - -void RelationDetailCacheAnalysis::run(const AstTranslationUnit& translationUnit) { - const auto& program = *translationUnit.getProgram(); - for (auto* rel : program.getRelations()) { - nameToRelation[rel->getQualifiedName()] = rel; - nameToClauses[rel->getQualifiedName()] = std::set(); - } - for (auto* clause : program.getClauses()) { - const auto& relationName = clause->getHead()->getQualifiedName(); - if (nameToClauses.find(relationName) == nameToClauses.end()) { - nameToClauses[relationName] = std::set(); - } - nameToClauses.at(relationName).insert(clause); - } -} - -void RelationDetailCacheAnalysis::print(std::ostream& os) const { - for (const auto& pair : nameToClauses) { - os << "--" << pair.first << "--"; - os << std::endl; - for (const auto* clause : pair.second) { - os << *clause << std::endl; - } - os << std::endl; - } -} - -void RecursiveClausesAnalysis::run(const AstTranslationUnit& translationUnit) { - visitDepthFirst(*translationUnit.getProgram(), [&](const AstClause& clause) { - if (computeIsRecursive(clause, translationUnit)) { - recursiveClauses.insert(&clause); - } - }); -} - -void RecursiveClausesAnalysis::print(std::ostream& os) const { - os << recursiveClauses << std::endl; -} - -bool RecursiveClausesAnalysis::computeIsRecursive( - const AstClause& clause, const AstTranslationUnit& translationUnit) const { - const auto& relationDetail = *translationUnit.getAnalysis(); - const AstProgram& program = *translationUnit.getProgram(); - - // we want to reach the atom of the head through the body - const AstRelation* trg = getHeadRelation(&clause, &program); - - std::set reached; - std::vector worklist; - - // set up start list - for (const auto* cur : getBodyLiterals(clause)) { - auto rel = relationDetail.getRelation(cur->getQualifiedName()); - if (rel == trg) { - return true; - } - worklist.push_back(rel); - } - - // process remaining elements - while (!worklist.empty()) { - // get next to process - const AstRelation* cur = worklist.back(); - worklist.pop_back(); - - // skip null pointers (errors in the input code) - if (cur == nullptr) { - continue; - } - - // check whether this one has been checked before - if (!reached.insert(cur).second) { - continue; - } - - // check all atoms in the relations - for (const AstClause* cl : relationDetail.getClauses(cur)) { - for (const AstAtom* at : getBodyLiterals(*cl)) { - auto rel = relationDetail.getRelation(at->getQualifiedName()); - if (rel == trg) { - return true; - } - worklist.push_back(rel); - } - } - } - - // no cycles found - return false; -} - -void SCCGraphAnalysis::run(const AstTranslationUnit& translationUnit) { - precedenceGraph = translationUnit.getAnalysis(); - ioType = translationUnit.getAnalysis(); - sccToRelation.clear(); - relationToScc.clear(); - predecessors.clear(); - successors.clear(); - - /* Compute SCC */ - std::vector relations = translationUnit.getProgram()->getRelations(); - size_t counter = 0; - size_t numSCCs = 0; - std::stack S; - std::stack P; - std::map preOrder; // Pre-order number of a node (for Gabow's Algo) - for (const AstRelation* relation : relations) { - relationToScc[relation] = preOrder[relation] = (size_t)-1; - } - for (const AstRelation* relation : relations) { - if (preOrder[relation] == (size_t)-1) { - scR(relation, preOrder, counter, S, P, numSCCs); - } - } - - /* Build SCC graph */ - successors.resize(numSCCs); - predecessors.resize(numSCCs); - for (const AstRelation* u : relations) { - for (const AstRelation* v : precedenceGraph->graph().predecessors(u)) { - auto scc_u = relationToScc[u]; - auto scc_v = relationToScc[v]; - assert(scc_u < numSCCs && "Wrong range"); - assert(scc_v < numSCCs && "Wrong range"); - if (scc_u != scc_v) { - predecessors[scc_u].insert(scc_v); - successors[scc_v].insert(scc_u); - } - } - } - - /* Store the relations for each SCC */ - sccToRelation.resize(numSCCs); - for (const AstRelation* relation : relations) { - sccToRelation[relationToScc[relation]].insert(relation); - } -} - -/* Compute strongly connected components using Gabow's algorithm (cf. Algorithms in - * Java by Robert Sedgewick / Part 5 / Graph * algorithms). The algorithm has linear - * runtime. */ -void SCCGraphAnalysis::scR(const AstRelation* w, std::map& preOrder, - size_t& counter, std::stack& S, std::stack& P, - size_t& numSCCs) { - preOrder[w] = counter++; - S.push(w); - P.push(w); - for (const AstRelation* t : precedenceGraph->graph().predecessors(w)) { - if (preOrder[t] == (size_t)-1) { - scR(t, preOrder, counter, S, P, numSCCs); - } else if (relationToScc[t] == (size_t)-1) { - while (preOrder[P.top()] > preOrder[t]) { - P.pop(); - } - } - } - if (P.top() == w) { - P.pop(); - } else { - return; - } - - const AstRelation* v; - do { - v = S.top(); - S.pop(); - relationToScc[v] = numSCCs; - } while (v != w); - numSCCs++; -} - -void SCCGraphAnalysis::print(std::ostream& os) const { - const std::string& name = Global::config().get("name"); - std::stringstream ss; - /* Print SCC graph */ - ss << "digraph {" << std::endl; - /* Print nodes of SCC graph */ - for (size_t scc = 0; scc < getNumberOfSCCs(); scc++) { - ss << "\t" << name << "_" << scc << "[label = \""; - ss << join(getInternalRelations(scc), ",\\n", - [](std::ostream& out, const AstRelation* rel) { out << rel->getQualifiedName(); }); - ss << "\" ];" << std::endl; - } - for (size_t scc = 0; scc < getNumberOfSCCs(); scc++) { - for (auto succ : getSuccessorSCCs(scc)) { - ss << "\t" << name << "_" << scc << " -> " << name << "_" << succ << ";" << std::endl; - } - } - ss << "}"; - printHTMLGraph(os, ss.str(), getName()); -} - -int TopologicallySortedSCCGraphAnalysis::topologicalOrderingCost( - const std::vector& permutationOfSCCs) const { - // create variables to hold the cost of the current SCC and the permutation as a whole - int costOfSCC = 0; - int costOfPermutation = -1; - // obtain an iterator to the end of the already ordered partition of sccs - auto it_k = permutationOfSCCs.begin() + sccOrder.size(); - // for each of the scc's in the ordering, resetting the cost of the scc to zero on each loop - for (auto it_i = permutationOfSCCs.begin(); it_i != permutationOfSCCs.end(); ++it_i, costOfSCC = 0) { - // if the index of the current scc is after the end of the ordered partition - if (it_i >= it_k) { - // check that the index of all predecessor sccs of are before the index of the current scc - for (auto scc : sccGraph->getPredecessorSCCs(*it_i)) { - if (std::find(permutationOfSCCs.begin(), it_i, scc) == it_i) { - // if not, the sort is not a valid topological sort - return -1; - } - } - } - // otherwise, calculate the cost of the current scc - // as the number of sccs with an index before the current scc - for (auto it_j = permutationOfSCCs.begin(); it_j != it_i; ++it_j) { - // having some successor scc with an index after the current scc - for (auto scc : sccGraph->getSuccessorSCCs(*it_j)) { - if (std::find(permutationOfSCCs.begin(), it_i, scc) == it_i) { - costOfSCC++; - } - } - } - // and if this cost is greater than the maximum recorded cost for the whole permutation so far, - // set the cost of the permutation to it - if (costOfSCC > costOfPermutation) { - costOfPermutation = costOfSCC; - } - } - return costOfPermutation; -} - -void TopologicallySortedSCCGraphAnalysis::computeTopologicalOrdering(size_t scc, std::vector& visited) { - // create a flag to indicate that a successor was visited (by default it hasn't been) - bool found = false; - bool hasUnvisitedSuccessor = false; - bool hasUnvisitedPredecessor = false; - // for each successor of the input scc - const auto& successorsToVisit = sccGraph->getSuccessorSCCs(scc); - for (const auto scc_i : successorsToVisit) { - if (visited[scc_i]) { - continue; - } - hasUnvisitedPredecessor = false; - const auto& successorsPredecessors = sccGraph->getPredecessorSCCs(scc_i); - for (const auto scc_j : successorsPredecessors) { - if (!visited[scc_j]) { - hasUnvisitedPredecessor = true; - break; - } - } - if (!hasUnvisitedPredecessor) { - // give it a temporary marking - visited[scc_i] = true; - // add it to the permanent ordering - sccOrder.push_back(scc_i); - // and use it as a root node in a recursive call to this function - computeTopologicalOrdering(scc_i, visited); - // finally, indicate that a successor has been found for this node - found = true; - } - } - // return at once if no valid successors have been found; as either it has none or they all have a - // better predecessor - if (!found) { - return; - } - hasUnvisitedPredecessor = false; - const auto& predecessors = sccGraph->getPredecessorSCCs(scc); - for (const auto scc_j : predecessors) { - if (!visited[scc_j]) { - hasUnvisitedPredecessor = true; - break; - } - } - hasUnvisitedSuccessor = false; - const auto& successors = sccGraph->getSuccessorSCCs(scc); - for (const auto scc_j : successors) { - if (!visited[scc_j]) { - hasUnvisitedSuccessor = true; - break; - } - } - // otherwise, if more white successors remain for the current scc, use it again as the root node in a - // recursive call to this function - if (hasUnvisitedSuccessor && !hasUnvisitedPredecessor) { - computeTopologicalOrdering(scc, visited); - } -} - -void TopologicallySortedSCCGraphAnalysis::run(const AstTranslationUnit& translationUnit) { - // obtain the scc graph - sccGraph = translationUnit.getAnalysis(); - // clear the list of ordered sccs - sccOrder.clear(); - std::vector visited; - visited.resize(sccGraph->getNumberOfSCCs()); - std::fill(visited.begin(), visited.end(), false); - // generate topological ordering using forwards algorithm (like Khan's algorithm) - // for each of the sccs in the graph - for (size_t scc = 0; scc < sccGraph->getNumberOfSCCs(); ++scc) { - // if that scc has no predecessors - if (sccGraph->getPredecessorSCCs(scc).empty()) { - // put it in the ordering - sccOrder.push_back(scc); - visited[scc] = true; - // if the scc has successors - if (!sccGraph->getSuccessorSCCs(scc).empty()) { - computeTopologicalOrdering(scc, visited); - } - } - } -} - -void TopologicallySortedSCCGraphAnalysis::print(std::ostream& os) const { - os << "--- partial order of strata as list of pairs ---" << std::endl; - for (size_t sccIndex = 0; sccIndex < sccOrder.size(); sccIndex++) { - const auto& successorSccs = sccGraph->getSuccessorSCCs(sccOrder.at(sccIndex)); - // use a self-loop to indicate that an SCC has no successors or predecessors - if (successorSccs.empty() && sccGraph->getPredecessorSCCs(sccOrder.at(sccIndex)).empty()) { - os << sccIndex << " " << sccIndex << std::endl; - continue; - } - for (const auto successorScc : successorSccs) { - const auto successorSccIndex = *std::find(sccOrder.begin(), sccOrder.end(), successorScc); - os << sccIndex << " " << successorSccIndex << std::endl; - } - } - os << "--- total order with relations of each strata ---" << std::endl; - for (size_t i = 0; i < sccOrder.size(); i++) { - os << i << ": ["; - os << join(sccGraph->getInternalRelations(sccOrder[i]), ", ", - [](std::ostream& out, const AstRelation* rel) { out << rel->getQualifiedName(); }); - os << "]" << std::endl; - } - os << std::endl; - os << "--- statistics of topological order ---" << std::endl; - os << "cost: " << topologicalOrderingCost(sccOrder) << std::endl; -} - -void RelationScheduleAnalysisStep::print(std::ostream& os) const { - os << "computed: "; - for (const AstRelation* compRel : computed()) { - os << compRel->getQualifiedName() << ", "; - } - os << "\nexpired: "; - for (const AstRelation* compRel : expired()) { - os << compRel->getQualifiedName() << ", "; - } - os << "\n"; - if (recursive()) { - os << "recursive"; - } else { - os << "not recursive"; - } - os << "\n"; -} - -void RelationScheduleAnalysis::run(const AstTranslationUnit& translationUnit) { - topsortSCCGraphAnalysis = translationUnit.getAnalysis(); - precedenceGraph = translationUnit.getAnalysis(); - - size_t numSCCs = translationUnit.getAnalysis()->getNumberOfSCCs(); - std::vector> relationExpirySchedule = - computeRelationExpirySchedule(translationUnit); - - relationSchedule.clear(); - for (size_t i = 0; i < numSCCs; i++) { - auto scc = topsortSCCGraphAnalysis->order()[i]; - const std::set computedRelations = - translationUnit.getAnalysis()->getInternalRelations(scc); - relationSchedule.emplace_back(computedRelations, relationExpirySchedule[i], - translationUnit.getAnalysis()->isRecursive(scc)); - } -} - -std::vector> RelationScheduleAnalysis::computeRelationExpirySchedule( - const AstTranslationUnit& translationUnit) { - std::vector> relationExpirySchedule; - /* Compute for each step in the reverse topological order - of evaluating the SCC the set of alive relations. */ - size_t numSCCs = topsortSCCGraphAnalysis->order().size(); - - /* Alive set for each step */ - std::vector> alive(numSCCs); - /* Resize expired relations sets */ - relationExpirySchedule.resize(numSCCs); - const auto& sccGraph = translationUnit.getAnalysis(); - - /* Compute all alive relations by iterating over all steps in reverse order - determine the dependencies */ - for (size_t orderedSCC = 1; orderedSCC < numSCCs; orderedSCC++) { - /* Add alive set of previous step */ - alive[orderedSCC].insert(alive[orderedSCC - 1].begin(), alive[orderedSCC - 1].end()); - - /* Add predecessors of relations computed in this step */ - auto scc = topsortSCCGraphAnalysis->order()[numSCCs - orderedSCC]; - for (const AstRelation* r : sccGraph->getInternalRelations(scc)) { - for (const AstRelation* predecessor : precedenceGraph->graph().predecessors(r)) { - alive[orderedSCC].insert(predecessor); - } - } - - /* Compute expired relations in reverse topological order using the set difference of the alive sets - between steps. */ - std::set_difference(alive[orderedSCC].begin(), alive[orderedSCC].end(), alive[orderedSCC - 1].begin(), - alive[orderedSCC - 1].end(), - std::inserter(relationExpirySchedule[numSCCs - orderedSCC], - relationExpirySchedule[numSCCs - orderedSCC].end())); - } - - return relationExpirySchedule; -} - -void RelationScheduleAnalysis::print(std::ostream& os) const { - os << "begin schedule\n"; - for (const RelationScheduleAnalysisStep& step : relationSchedule) { - os << step; - os << "computed: "; - for (const AstRelation* compRel : step.computed()) { - os << compRel->getQualifiedName() << ", "; - } - os << "\nexpired: "; - for (const AstRelation* compRel : step.expired()) { - os << compRel->getQualifiedName() << ", "; - } - os << "\n"; - if (step.recursive()) { - os << "recursive"; - } else { - os << "not recursive"; - } - os << "\n"; - } - os << "end schedule\n"; -} - } // end of namespace souffle diff --git a/src/ast/analysis/PrecedenceGraph.h b/src/ast/analysis/PrecedenceGraph.h index f94b7ae3f87..a0f433a00a8 100644 --- a/src/ast/analysis/PrecedenceGraph.h +++ b/src/ast/analysis/PrecedenceGraph.h @@ -19,25 +19,13 @@ #pragma once #include "GraphUtils.h" -#include "ast/AstQualifiedName.h" #include "ast/AstRelation.h" #include "ast/analysis/AstAnalysis.h" -#include "ast/analysis/AstIOTypeAnalysis.h" -#include -#include -#include #include -#include -#include -#include -#include #include -#include -#include namespace souffle { -class AstClause; class AstTranslationUnit; /** @@ -63,396 +51,4 @@ class PrecedenceGraphAnalysis : public AstAnalysis { Graph backingGraph; }; -/** - * Analysis pass identifying relations which do not contribute to the computation - * of the output relations. - */ -class RedundantRelationsAnalysis : public AstAnalysis { -public: - static constexpr const char* name = "redundant-relations"; - - RedundantRelationsAnalysis() : AstAnalysis(name) {} - - void run(const AstTranslationUnit& translationUnit) override; - - void print(std::ostream& os) const override; - - const std::set& getRedundantRelations() const { - return redundantRelations; - } - -private: - PrecedenceGraphAnalysis* precedenceGraph = nullptr; - - std::set redundantRelations; -}; - -/** - * Analysis pass identifying clauses which are recursive. - */ -class RecursiveClausesAnalysis : public AstAnalysis { -public: - static constexpr const char* name = "recursive-clauses"; - - RecursiveClausesAnalysis() : AstAnalysis(name) {} - - void run(const AstTranslationUnit& translationUnit) override; - - void print(std::ostream& os) const override; - - bool recursive(const AstClause* clause) const { - return recursiveClauses.count(clause) != 0u; - } - -private: - std::set recursiveClauses; - - /** Determines whether the given clause is recursive within the given program */ - bool computeIsRecursive(const AstClause& clause, const AstTranslationUnit& translationUnit) const; -}; - -/** - * Analysis pass mapping identifiers with relations and clauses. - */ -class RelationDetailCacheAnalysis : public AstAnalysis { -public: - static constexpr const char* name = "relation-detail"; - - RelationDetailCacheAnalysis() : AstAnalysis(name) {} - - void run(const AstTranslationUnit& translationUnit) override; - - void print(std::ostream& os) const override; - - AstRelation* getRelation(const AstQualifiedName& name) const { - if (nameToRelation.find(name) != nameToRelation.end()) { - return nameToRelation.at(name); - } - return nullptr; - } - - std::set getClauses(const AstRelation* rel) const { - assert(rel != nullptr && "invalid relation"); - return getClauses(rel->getQualifiedName()); - } - - std::set getClauses(const AstQualifiedName& name) const { - if (nameToClauses.find(name) != nameToClauses.end()) { - return nameToClauses.at(name); - } - return std::set(); - } - -private: - std::map nameToRelation; - std::map> nameToClauses; -}; - -/** - * Analysis pass computing the strongly connected component (SCC) graph for the datalog program. - */ -class SCCGraphAnalysis : public AstAnalysis { -public: - static constexpr const char* name = "scc-graph"; - - SCCGraphAnalysis() : AstAnalysis(name) {} - - void run(const AstTranslationUnit& translationUnit) override; - - /** Get the number of SCCs in the graph. */ - size_t getNumberOfSCCs() const { - return sccToRelation.size(); - } - - /** Get the SCC of the given relation. */ - size_t getSCC(const AstRelation* rel) const { - return relationToScc.at(rel); - } - - /** Get all successor SCCs of a given SCC. */ - const std::set& getSuccessorSCCs(const size_t scc) const { - return successors.at(scc); - } - - /** Get all predecessor SCCs of a given SCC. */ - const std::set& getPredecessorSCCs(const size_t scc) const { - return predecessors.at(scc); - } - - /** Get all SCCs containing a successor of a given relation. */ - std::set getSuccessorSCCs(const AstRelation* relation) const { - std::set successorSccs; - const auto scc = relationToScc.at(relation); - for (const auto& successor : precedenceGraph->graph().successors(relation)) { - const auto successorScc = relationToScc.at(successor); - if (successorScc != scc) { - successorSccs.insert(successorScc); - } - } - return successorSccs; - } - - /** Get all SCCs containing a predecessor of a given relation. */ - std::set getPredecessorSCCs(const AstRelation* relation) const { - std::set predecessorSccs; - const auto scc = relationToScc.at(relation); - for (const auto& predecessor : precedenceGraph->graph().predecessors(relation)) { - const auto predecessorScc = relationToScc.at(predecessor); - if (predecessorScc != scc) { - predecessorSccs.insert(predecessorScc); - } - } - return predecessorSccs; - } - - /** Get all internal relations of a given SCC. */ - const std::set& getInternalRelations(const size_t scc) const { - return sccToRelation.at(scc); - } - - /** Get all external output predecessor relations of a given SCC. */ - std::set getExternalOutputPredecessorRelations(const size_t scc) const { - std::set externOutPreds; - for (const auto& relation : getInternalRelations(scc)) { - for (const auto& predecessor : precedenceGraph->graph().predecessors(relation)) { - if (relationToScc.at(predecessor) != scc && ioType->isOutput(predecessor)) { - externOutPreds.insert(predecessor); - } - } - } - return externOutPreds; - } - - /** Get all external non-output predecessor relations of a given SCC. */ - std::set getExternalNonOutputPredecessorRelations(const size_t scc) const { - std::set externNonOutPreds; - for (const auto& relation : getInternalRelations(scc)) { - for (const auto& predecessor : precedenceGraph->graph().predecessors(relation)) { - if (relationToScc.at(predecessor) != scc && !ioType->isOutput(predecessor)) { - externNonOutPreds.insert(predecessor); - } - } - } - return externNonOutPreds; - } - - /** Get all external predecessor relations of a given SCC. */ - std::set getExternalPredecessorRelations(const size_t scc) const { - std::set externPreds; - for (const auto& relation : getInternalRelations(scc)) { - for (const auto& predecessor : precedenceGraph->graph().predecessors(relation)) { - if (relationToScc.at(predecessor) != scc) { - externPreds.insert(predecessor); - } - } - } - return externPreds; - } - - /** Get all internal output relations of a given SCC. */ - std::set getInternalOutputRelations(const size_t scc) const { - std::set internOuts; - for (const auto& relation : getInternalRelations(scc)) { - if (ioType->isOutput(relation)) { - internOuts.insert(relation); - } - } - return internOuts; - } - - /** Get all internal relations of a given SCC with external successors. */ - std::set getInternalRelationsWithExternalSuccessors(const size_t scc) const { - std::set internsWithExternSuccs; - for (const auto& relation : getInternalRelations(scc)) { - for (const auto& successor : precedenceGraph->graph().successors(relation)) { - if (relationToScc.at(successor) != scc) { - internsWithExternSuccs.insert(relation); - break; - } - } - } - return internsWithExternSuccs; - } - - /** Get all internal non-output relations of a given SCC with external successors. */ - std::set getInternalNonOutputRelationsWithExternalSuccessors(const size_t scc) const { - std::set internNonOutsWithExternSuccs; - for (const auto& relation : getInternalRelations(scc)) { - if (!ioType->isOutput(relation)) { - for (const auto& successor : precedenceGraph->graph().successors(relation)) { - if (relationToScc.at(successor) != scc) { - internNonOutsWithExternSuccs.insert(relation); - break; - } - } - } - } - return internNonOutsWithExternSuccs; - } - - /** Get all internal input relations of a given SCC. */ - std::set getInternalInputRelations(const size_t scc) const { - std::set internIns; - for (const auto& relation : getInternalRelations(scc)) { - if (ioType->isInput(relation)) { - internIns.insert(relation); - } - } - return internIns; - } - - /** Return if the given SCC is recursive. */ - bool isRecursive(const size_t scc) const { - const std::set& sccRelations = sccToRelation.at(scc); - if (sccRelations.size() == 1) { - const AstRelation* singleRelation = *sccRelations.begin(); - if (precedenceGraph->graph().predecessors(singleRelation).count(singleRelation) == 0u) { - return false; - } - } - return true; - } - - /** Print the SCC graph. */ - void print(std::ostream& os) const override; - -private: - PrecedenceGraphAnalysis* precedenceGraph = nullptr; - - /** Map from node number to SCC number */ - std::map relationToScc; - - /** Adjacency lists for the SCC graph */ - std::vector> successors; - - /** Predecessor set for the SCC graph */ - std::vector> predecessors; - - /** Relations contained in a SCC */ - std::vector> sccToRelation; - - /** Recursive scR method for computing SCC */ - void scR(const AstRelation* relation, std::map& preOrder, size_t& counter, - std::stack& S, std::stack& P, size_t& numSCCs); - - IOType* ioType = nullptr; -}; - -/** - * Analysis pass computing a topologically sorted strongly connected component (SCC) graph. - */ -class TopologicallySortedSCCGraphAnalysis : public AstAnalysis { -public: - static constexpr const char* name = "topological-scc-graph"; - - TopologicallySortedSCCGraphAnalysis() : AstAnalysis(name) {} - - void run(const AstTranslationUnit& translationUnit) override; - - const std::vector& order() const { - return sccOrder; - } - - size_t sccOfIndex(const size_t index) const { - return sccOrder.at(index); - } - - size_t indexOfScc(const size_t scc) const { - auto it = std::find(sccOrder.begin(), sccOrder.end(), scc); - assert(it != sccOrder.end()); - return (size_t)std::distance(sccOrder.begin(), it); - } - - std::set indexOfScc(const std::set& sccs) const { - std::set indices; - for (const auto scc : sccs) { - indices.insert(indexOfScc(scc)); - } - return indices; - } - - /** Output topologically sorted strongly connected component graph in text format */ - void print(std::ostream& os) const override; - -private: - /** The strongly connected component (SCC) graph. */ - SCCGraphAnalysis* sccGraph = nullptr; - - /** The final topological ordering of the SCCs. */ - std::vector sccOrder; - - /** Calculate the topological ordering cost of a permutation of as of yet unordered SCCs - using the ordered SCCs. Returns -1 if the given vector is not a valid topological ordering. */ - int topologicalOrderingCost(const std::vector& permutationOfSCCs) const; - - /** Recursive component for the forwards algorithm computing the topological ordering of the SCCs. */ - void computeTopologicalOrdering(size_t scc, std::vector& visited); -}; - -/** - * A single step in a relation schedule, consisting of the relations computed in the step - * and the relations that are no longer required at that step. - */ -class RelationScheduleAnalysisStep { -public: - RelationScheduleAnalysisStep(std::set computedRelations, - std::set expiredRelations, const bool isRecursive) - : computedRelations(std::move(computedRelations)), expiredRelations(std::move(expiredRelations)), - isRecursive(isRecursive) {} - - const std::set& computed() const { - return computedRelations; - } - - const std::set& expired() const { - return expiredRelations; - } - - bool recursive() const { - return isRecursive; - } - - void print(std::ostream& os) const; - - /** Add support for printing nodes */ - friend std::ostream& operator<<(std::ostream& out, const RelationScheduleAnalysisStep& other) { - other.print(out); - return out; - } - -private: - std::set computedRelations; - std::set expiredRelations; - const bool isRecursive; -}; - -/** - * Analysis pass computing a schedule for computing relations. - */ -class RelationScheduleAnalysis : public AstAnalysis { -public: - static constexpr const char* name = "relation-schedule"; - - RelationScheduleAnalysis() : AstAnalysis(name) {} - - void run(const AstTranslationUnit& translationUnit) override; - - const std::vector& schedule() const { - return relationSchedule; - } - - /** Dump this relation schedule to standard error. */ - void print(std::ostream& os) const override; - -private: - TopologicallySortedSCCGraphAnalysis* topsortSCCGraphAnalysis = nullptr; - PrecedenceGraphAnalysis* precedenceGraph = nullptr; - - /** Relations computed and expired relations at each step */ - std::vector relationSchedule; - - std::vector> computeRelationExpirySchedule( - const AstTranslationUnit& translationUnit); -}; - } // end of namespace souffle diff --git a/src/ast/analysis/RecursiveClauses.cpp b/src/ast/analysis/RecursiveClauses.cpp new file mode 100644 index 00000000000..beff61642b1 --- /dev/null +++ b/src/ast/analysis/RecursiveClauses.cpp @@ -0,0 +1,101 @@ +/* + * Souffle - A Datalog Compiler + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved + * Licensed under the Universal Permissive License v 1.0 as shown at: + * - https://opensource.org/licenses/UPL + * - /licenses/SOUFFLE-UPL.txt + */ + +/************************************************************************ + * + * @file RecursiveClauses.cpp + * + * Implements method of precedence graph to build the precedence graph, + * compute strongly connected components of the precedence graph, and + * build the strongly connected component graph. + * + ***********************************************************************/ + +#include "ast/analysis/RecursiveClauses.h" +#include "ast/AstClause.h" +#include "ast/AstLiteral.h" +#include "ast/AstNode.h" +#include "ast/AstProgram.h" +#include "ast/AstTranslationUnit.h" +#include "ast/AstUtils.h" +#include "ast/AstVisitor.h" +#include "ast/analysis/RelationDetailCache.h" +#include "utility/StreamUtil.h" +#include +#include +#include +#include + +namespace souffle { +class AstRelation; + +void RecursiveClausesAnalysis::run(const AstTranslationUnit& translationUnit) { + visitDepthFirst(*translationUnit.getProgram(), [&](const AstClause& clause) { + if (computeIsRecursive(clause, translationUnit)) { + recursiveClauses.insert(&clause); + } + }); +} + +void RecursiveClausesAnalysis::print(std::ostream& os) const { + os << recursiveClauses << std::endl; +} + +bool RecursiveClausesAnalysis::computeIsRecursive( + const AstClause& clause, const AstTranslationUnit& translationUnit) const { + const auto& relationDetail = *translationUnit.getAnalysis(); + const AstProgram& program = *translationUnit.getProgram(); + + // we want to reach the atom of the head through the body + const AstRelation* trg = getHeadRelation(&clause, &program); + + std::set reached; + std::vector worklist; + + // set up start list + for (const auto* cur : getBodyLiterals(clause)) { + auto rel = relationDetail.getRelation(cur->getQualifiedName()); + if (rel == trg) { + return true; + } + worklist.push_back(rel); + } + + // process remaining elements + while (!worklist.empty()) { + // get next to process + const AstRelation* cur = worklist.back(); + worklist.pop_back(); + + // skip null pointers (errors in the input code) + if (cur == nullptr) { + continue; + } + + // check whether this one has been checked before + if (!reached.insert(cur).second) { + continue; + } + + // check all atoms in the relations + for (const AstClause* cl : relationDetail.getClauses(cur)) { + for (const AstAtom* at : getBodyLiterals(*cl)) { + auto rel = relationDetail.getRelation(at->getQualifiedName()); + if (rel == trg) { + return true; + } + worklist.push_back(rel); + } + } + } + + // no cycles found + return false; +} + +} // end of namespace souffle diff --git a/src/ast/analysis/RecursiveClauses.h b/src/ast/analysis/RecursiveClauses.h new file mode 100644 index 00000000000..ddd6a9bd817 --- /dev/null +++ b/src/ast/analysis/RecursiveClauses.h @@ -0,0 +1,55 @@ +/* + * Souffle - A Datalog Compiler + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved + * Licensed under the Universal Permissive License v 1.0 as shown at: + * - https://opensource.org/licenses/UPL + * - /licenses/SOUFFLE-UPL.txt + */ + +/************************************************************************ + * + * @file RecursiveClauses.h + * + * Defines the class to build the precedence graph, + * compute strongly connected components of the precedence graph, and + * build the strongly connected component graph. + * + ***********************************************************************/ + +#pragma once + +#include "ast/analysis/AstAnalysis.h" +#include +#include +#include + +namespace souffle { + +class AstClause; +class AstTranslationUnit; + +/** + * Analysis pass identifying clauses which are recursive. + */ +class RecursiveClausesAnalysis : public AstAnalysis { +public: + static constexpr const char* name = "recursive-clauses"; + + RecursiveClausesAnalysis() : AstAnalysis(name) {} + + void run(const AstTranslationUnit& translationUnit) override; + + void print(std::ostream& os) const override; + + bool recursive(const AstClause* clause) const { + return recursiveClauses.count(clause) != 0u; + } + +private: + std::set recursiveClauses; + + /** Determines whether the given clause is recursive within the given program */ + bool computeIsRecursive(const AstClause& clause, const AstTranslationUnit& translationUnit) const; +}; + +} // end of namespace souffle diff --git a/src/ast/analysis/RedundantRelations.cpp b/src/ast/analysis/RedundantRelations.cpp new file mode 100644 index 00000000000..fcda60192f3 --- /dev/null +++ b/src/ast/analysis/RedundantRelations.cpp @@ -0,0 +1,78 @@ +/* + * Souffle - A Datalog Compiler + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved + * Licensed under the Universal Permissive License v 1.0 as shown at: + * - https://opensource.org/licenses/UPL + * - /licenses/SOUFFLE-UPL.txt + */ + +/************************************************************************ + * + * @file RedundantRelations.cpp + * + * Implements method of precedence graph to build the precedence graph, + * compute strongly connected components of the precedence graph, and + * build the strongly connected component graph. + * + ***********************************************************************/ + +#include "ast/analysis/RedundantRelations.h" +#include "GraphUtils.h" +#include "ast/AstNode.h" +#include "ast/AstProgram.h" +#include "ast/AstRelation.h" +#include "ast/AstTranslationUnit.h" +#include "ast/analysis/AstIOType.h" +#include "ast/analysis/PrecedenceGraph.h" +#include "utility/StreamUtil.h" +#include +#include + +namespace souffle { + +void RedundantRelationsAnalysis::run(const AstTranslationUnit& translationUnit) { + precedenceGraph = translationUnit.getAnalysis(); + + std::set work; + std::set notRedundant; + auto* ioType = translationUnit.getAnalysis(); + + const std::vector& relations = translationUnit.getProgram()->getRelations(); + /* Add all output relations to the work set */ + for (const AstRelation* r : relations) { + if (ioType->isOutput(r)) { + work.insert(r); + } + } + + /* Find all relations which are not redundant for the computations of the + output relations. */ + while (!work.empty()) { + /* Chose one element in the work set and add it to notRedundant */ + const AstRelation* u = *(work.begin()); + work.erase(work.begin()); + notRedundant.insert(u); + + /* Find all predecessors of u and add them to the worklist + if they are not in the set notRedundant */ + for (const AstRelation* predecessor : precedenceGraph->graph().predecessors(u)) { + if (notRedundant.count(predecessor) == 0u) { + work.insert(predecessor); + } + } + } + + /* All remaining relations are redundant. */ + redundantRelations.clear(); + for (const AstRelation* r : relations) { + if (notRedundant.count(r) == 0u) { + redundantRelations.insert(r); + } + } +} + +void RedundantRelationsAnalysis::print(std::ostream& os) const { + os << redundantRelations << std::endl; +} + +} // end of namespace souffle diff --git a/src/ast/analysis/RedundantRelations.h b/src/ast/analysis/RedundantRelations.h new file mode 100644 index 00000000000..df34c50ef30 --- /dev/null +++ b/src/ast/analysis/RedundantRelations.h @@ -0,0 +1,55 @@ +/* + * Souffle - A Datalog Compiler + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved + * Licensed under the Universal Permissive License v 1.0 as shown at: + * - https://opensource.org/licenses/UPL + * - /licenses/SOUFFLE-UPL.txt + */ + +/************************************************************************ + * + * @file RedundantRelations.h + * + * Defines the class to build the precedence graph, + * compute strongly connected components of the precedence graph, and + * build the strongly connected component graph. + * + ***********************************************************************/ + +#pragma once + +#include "ast/analysis/AstAnalysis.h" +#include +#include +#include + +namespace souffle { +class AstTranslationUnit; +class PrecedenceGraphAnalysis; +class AstRelation; + +/** + * Analysis pass identifying relations which do not contribute to the computation + * of the output relations. + */ +class RedundantRelationsAnalysis : public AstAnalysis { +public: + static constexpr const char* name = "redundant-relations"; + + RedundantRelationsAnalysis() : AstAnalysis(name) {} + + void run(const AstTranslationUnit& translationUnit) override; + + void print(std::ostream& os) const override; + + const std::set& getRedundantRelations() const { + return redundantRelations; + } + +private: + PrecedenceGraphAnalysis* precedenceGraph = nullptr; + + std::set redundantRelations; +}; + +} // end of namespace souffle diff --git a/src/ast/analysis/RelationDetailCache.cpp b/src/ast/analysis/RelationDetailCache.cpp new file mode 100644 index 00000000000..1b0c57c6c83 --- /dev/null +++ b/src/ast/analysis/RelationDetailCache.cpp @@ -0,0 +1,59 @@ +/* + * Souffle - A Datalog Compiler + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved + * Licensed under the Universal Permissive License v 1.0 as shown at: + * - https://opensource.org/licenses/UPL + * - /licenses/SOUFFLE-UPL.txt + */ + +/************************************************************************ + * + * @file RelationDetailCache.cpp + * + * Implements method of precedence graph to build the precedence graph, + * compute strongly connected components of the precedence graph, and + * build the strongly connected component graph. + * + ***********************************************************************/ + +#include "ast/analysis/RelationDetailCache.h" +#include "ast/AstClause.h" +#include "ast/AstLiteral.h" +#include "ast/AstNode.h" +#include "ast/AstProgram.h" +#include "ast/AstQualifiedName.h" +#include "ast/AstRelation.h" +#include "ast/AstTranslationUnit.h" +#include +#include +#include + +namespace souffle { + +void RelationDetailCacheAnalysis::run(const AstTranslationUnit& translationUnit) { + const auto& program = *translationUnit.getProgram(); + for (auto* rel : program.getRelations()) { + nameToRelation[rel->getQualifiedName()] = rel; + nameToClauses[rel->getQualifiedName()] = std::set(); + } + for (auto* clause : program.getClauses()) { + const auto& relationName = clause->getHead()->getQualifiedName(); + if (nameToClauses.find(relationName) == nameToClauses.end()) { + nameToClauses[relationName] = std::set(); + } + nameToClauses.at(relationName).insert(clause); + } +} + +void RelationDetailCacheAnalysis::print(std::ostream& os) const { + for (const auto& pair : nameToClauses) { + os << "--" << pair.first << "--"; + os << std::endl; + for (const auto* clause : pair.second) { + os << *clause << std::endl; + } + os << std::endl; + } +} + +} // end of namespace souffle diff --git a/src/ast/analysis/RelationDetailCache.h b/src/ast/analysis/RelationDetailCache.h new file mode 100644 index 00000000000..5ad97af0b03 --- /dev/null +++ b/src/ast/analysis/RelationDetailCache.h @@ -0,0 +1,72 @@ +/* + * Souffle - A Datalog Compiler + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved + * Licensed under the Universal Permissive License v 1.0 as shown at: + * - https://opensource.org/licenses/UPL + * - /licenses/SOUFFLE-UPL.txt + */ + +/************************************************************************ + * + * @file RelationDetailCache.h + * + * Defines the class to build the precedence graph, + * compute strongly connected components of the precedence graph, and + * build the strongly connected component graph. + * + ***********************************************************************/ + +#pragma once + +#include "ast/AstQualifiedName.h" +#include "ast/AstRelation.h" +#include "ast/analysis/AstAnalysis.h" +#include +#include +#include +#include +#include + +namespace souffle { + +class AstClause; +class AstTranslationUnit; + +/** + * Analysis pass mapping identifiers with relations and clauses. + */ +class RelationDetailCacheAnalysis : public AstAnalysis { +public: + static constexpr const char* name = "relation-detail"; + + RelationDetailCacheAnalysis() : AstAnalysis(name) {} + + void run(const AstTranslationUnit& translationUnit) override; + + void print(std::ostream& os) const override; + + AstRelation* getRelation(const AstQualifiedName& name) const { + if (nameToRelation.find(name) != nameToRelation.end()) { + return nameToRelation.at(name); + } + return nullptr; + } + + std::set getClauses(const AstRelation* rel) const { + assert(rel != nullptr && "invalid relation"); + return getClauses(rel->getQualifiedName()); + } + + std::set getClauses(const AstQualifiedName& name) const { + if (nameToClauses.find(name) != nameToClauses.end()) { + return nameToClauses.at(name); + } + return std::set(); + } + +private: + std::map nameToRelation; + std::map> nameToClauses; +}; + +} // end of namespace souffle diff --git a/src/ast/analysis/RelationSchedule.cpp b/src/ast/analysis/RelationSchedule.cpp new file mode 100644 index 00000000000..5c30b93ecf7 --- /dev/null +++ b/src/ast/analysis/RelationSchedule.cpp @@ -0,0 +1,132 @@ +/* + * Souffle - A Datalog Compiler + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved + * Licensed under the Universal Permissive License v 1.0 as shown at: + * - https://opensource.org/licenses/UPL + * - /licenses/SOUFFLE-UPL.txt + */ + +/************************************************************************ + * + * @file RelationSchedule.cpp + * + * Implements method of precedence graph to build the precedence graph, + * compute strongly connected components of the precedence graph, and + * build the strongly connected component graph. + * + ***********************************************************************/ + +#include "ast/analysis/RelationSchedule.h" +#include "GraphUtils.h" +#include "ast/AstQualifiedName.h" +#include "ast/AstRelation.h" +#include "ast/AstTranslationUnit.h" +#include "ast/analysis/PrecedenceGraph.h" +#include "ast/analysis/SCCGraph.h" +#include "ast/analysis/TopologicallySortedSCCGraph.h" +#include +#include +#include +#include +#include + +namespace souffle { + +void RelationScheduleAnalysisStep::print(std::ostream& os) const { + os << "computed: "; + for (const AstRelation* compRel : computed()) { + os << compRel->getQualifiedName() << ", "; + } + os << "\nexpired: "; + for (const AstRelation* compRel : expired()) { + os << compRel->getQualifiedName() << ", "; + } + os << "\n"; + if (recursive()) { + os << "recursive"; + } else { + os << "not recursive"; + } + os << "\n"; +} + +void RelationScheduleAnalysis::run(const AstTranslationUnit& translationUnit) { + topsortSCCGraphAnalysis = translationUnit.getAnalysis(); + precedenceGraph = translationUnit.getAnalysis(); + + size_t numSCCs = translationUnit.getAnalysis()->getNumberOfSCCs(); + std::vector> relationExpirySchedule = + computeRelationExpirySchedule(translationUnit); + + relationSchedule.clear(); + for (size_t i = 0; i < numSCCs; i++) { + auto scc = topsortSCCGraphAnalysis->order()[i]; + const std::set computedRelations = + translationUnit.getAnalysis()->getInternalRelations(scc); + relationSchedule.emplace_back(computedRelations, relationExpirySchedule[i], + translationUnit.getAnalysis()->isRecursive(scc)); + } +} + +std::vector> RelationScheduleAnalysis::computeRelationExpirySchedule( + const AstTranslationUnit& translationUnit) { + std::vector> relationExpirySchedule; + /* Compute for each step in the reverse topological order + of evaluating the SCC the set of alive relations. */ + size_t numSCCs = topsortSCCGraphAnalysis->order().size(); + + /* Alive set for each step */ + std::vector> alive(numSCCs); + /* Resize expired relations sets */ + relationExpirySchedule.resize(numSCCs); + const auto& sccGraph = translationUnit.getAnalysis(); + + /* Compute all alive relations by iterating over all steps in reverse order + determine the dependencies */ + for (size_t orderedSCC = 1; orderedSCC < numSCCs; orderedSCC++) { + /* Add alive set of previous step */ + alive[orderedSCC].insert(alive[orderedSCC - 1].begin(), alive[orderedSCC - 1].end()); + + /* Add predecessors of relations computed in this step */ + auto scc = topsortSCCGraphAnalysis->order()[numSCCs - orderedSCC]; + for (const AstRelation* r : sccGraph->getInternalRelations(scc)) { + for (const AstRelation* predecessor : precedenceGraph->graph().predecessors(r)) { + alive[orderedSCC].insert(predecessor); + } + } + + /* Compute expired relations in reverse topological order using the set difference of the alive sets + between steps. */ + std::set_difference(alive[orderedSCC].begin(), alive[orderedSCC].end(), alive[orderedSCC - 1].begin(), + alive[orderedSCC - 1].end(), + std::inserter(relationExpirySchedule[numSCCs - orderedSCC], + relationExpirySchedule[numSCCs - orderedSCC].end())); + } + + return relationExpirySchedule; +} + +void RelationScheduleAnalysis::print(std::ostream& os) const { + os << "begin schedule\n"; + for (const RelationScheduleAnalysisStep& step : relationSchedule) { + os << step; + os << "computed: "; + for (const AstRelation* compRel : step.computed()) { + os << compRel->getQualifiedName() << ", "; + } + os << "\nexpired: "; + for (const AstRelation* compRel : step.expired()) { + os << compRel->getQualifiedName() << ", "; + } + os << "\n"; + if (step.recursive()) { + os << "recursive"; + } else { + os << "not recursive"; + } + os << "\n"; + } + os << "end schedule\n"; +} + +} // end of namespace souffle diff --git a/src/ast/analysis/RelationSchedule.h b/src/ast/analysis/RelationSchedule.h new file mode 100644 index 00000000000..5b10ae6f13d --- /dev/null +++ b/src/ast/analysis/RelationSchedule.h @@ -0,0 +1,101 @@ +/* + * Souffle - A Datalog Compiler + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved + * Licensed under the Universal Permissive License v 1.0 as shown at: + * - https://opensource.org/licenses/UPL + * - /licenses/SOUFFLE-UPL.txt + */ + +/************************************************************************ + * + * @file RelationSchedule.h + * + * Defines the class to build the precedence graph, + * compute strongly connected components of the precedence graph, and + * build the strongly connected component graph. + * + ***********************************************************************/ + +#pragma once + +#include "ast/analysis/AstAnalysis.h" +#include +#include +#include +#include +#include + +namespace souffle { + +class AstTranslationUnit; +class PrecedenceGraphAnalysis; +class TopologicallySortedSCCGraphAnalysis; +class AstRelation; + +/** + * A single step in a relation schedule, consisting of the relations computed in the step + * and the relations that are no longer required at that step. + */ +class RelationScheduleAnalysisStep { +public: + RelationScheduleAnalysisStep(std::set computedRelations, + std::set expiredRelations, const bool isRecursive) + : computedRelations(std::move(computedRelations)), expiredRelations(std::move(expiredRelations)), + isRecursive(isRecursive) {} + + const std::set& computed() const { + return computedRelations; + } + + const std::set& expired() const { + return expiredRelations; + } + + bool recursive() const { + return isRecursive; + } + + void print(std::ostream& os) const; + + /** Add support for printing nodes */ + friend std::ostream& operator<<(std::ostream& out, const RelationScheduleAnalysisStep& other) { + other.print(out); + return out; + } + +private: + std::set computedRelations; + std::set expiredRelations; + const bool isRecursive; +}; + +/** + * Analysis pass computing a schedule for computing relations. + */ +class RelationScheduleAnalysis : public AstAnalysis { +public: + static constexpr const char* name = "relation-schedule"; + + RelationScheduleAnalysis() : AstAnalysis(name) {} + + void run(const AstTranslationUnit& translationUnit) override; + + const std::vector& schedule() const { + return relationSchedule; + } + + /** Dump this relation schedule to standard error. */ + void print(std::ostream& os) const override; + +private: + TopologicallySortedSCCGraphAnalysis* topsortSCCGraphAnalysis = nullptr; + PrecedenceGraphAnalysis* precedenceGraph = nullptr; + + /** Relations computed and expired relations at each step */ + std::vector relationSchedule; + + std::vector> computeRelationExpirySchedule( + const AstTranslationUnit& translationUnit); +}; + +} // end of namespace souffle diff --git a/src/ast/analysis/SCCGraph.cpp b/src/ast/analysis/SCCGraph.cpp new file mode 100644 index 00000000000..a5bf518989d --- /dev/null +++ b/src/ast/analysis/SCCGraph.cpp @@ -0,0 +1,137 @@ +/* + * Souffle - A Datalog Compiler + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved + * Licensed under the Universal Permissive License v 1.0 as shown at: + * - https://opensource.org/licenses/UPL + * - /licenses/SOUFFLE-UPL.txt + */ + +/************************************************************************ + * + * @file SCCGraph.cpp + * + * Implements method of precedence graph to build the precedence graph, + * compute strongly connected components of the precedence graph, and + * build the strongly connected component graph. + * + ***********************************************************************/ + +#include "ast/analysis/SCCGraph.h" +#include "Global.h" +#include "GraphUtils.h" +#include "ast/AstProgram.h" +#include "ast/AstQualifiedName.h" +#include "ast/AstRelation.h" +#include "ast/AstTranslationUnit.h" +#include "ast/analysis/AstIOType.h" +#include "utility/StreamUtil.h" +#include +#include +#include +#include +#include + +namespace souffle { + +void SCCGraphAnalysis::run(const AstTranslationUnit& translationUnit) { + precedenceGraph = translationUnit.getAnalysis(); + ioType = translationUnit.getAnalysis(); + sccToRelation.clear(); + relationToScc.clear(); + predecessors.clear(); + successors.clear(); + + /* Compute SCC */ + std::vector relations = translationUnit.getProgram()->getRelations(); + size_t counter = 0; + size_t numSCCs = 0; + std::stack S; + std::stack P; + std::map preOrder; // Pre-order number of a node (for Gabow's Algo) + for (const AstRelation* relation : relations) { + relationToScc[relation] = preOrder[relation] = (size_t)-1; + } + for (const AstRelation* relation : relations) { + if (preOrder[relation] == (size_t)-1) { + scR(relation, preOrder, counter, S, P, numSCCs); + } + } + + /* Build SCC graph */ + successors.resize(numSCCs); + predecessors.resize(numSCCs); + for (const AstRelation* u : relations) { + for (const AstRelation* v : precedenceGraph->graph().predecessors(u)) { + auto scc_u = relationToScc[u]; + auto scc_v = relationToScc[v]; + assert(scc_u < numSCCs && "Wrong range"); + assert(scc_v < numSCCs && "Wrong range"); + if (scc_u != scc_v) { + predecessors[scc_u].insert(scc_v); + successors[scc_v].insert(scc_u); + } + } + } + + /* Store the relations for each SCC */ + sccToRelation.resize(numSCCs); + for (const AstRelation* relation : relations) { + sccToRelation[relationToScc[relation]].insert(relation); + } +} + +/* Compute strongly connected components using Gabow's algorithm (cf. Algorithms in + * Java by Robert Sedgewick / Part 5 / Graph * algorithms). The algorithm has linear + * runtime. */ +void SCCGraphAnalysis::scR(const AstRelation* w, std::map& preOrder, + size_t& counter, std::stack& S, std::stack& P, + size_t& numSCCs) { + preOrder[w] = counter++; + S.push(w); + P.push(w); + for (const AstRelation* t : precedenceGraph->graph().predecessors(w)) { + if (preOrder[t] == (size_t)-1) { + scR(t, preOrder, counter, S, P, numSCCs); + } else if (relationToScc[t] == (size_t)-1) { + while (preOrder[P.top()] > preOrder[t]) { + P.pop(); + } + } + } + if (P.top() == w) { + P.pop(); + } else { + return; + } + + const AstRelation* v; + do { + v = S.top(); + S.pop(); + relationToScc[v] = numSCCs; + } while (v != w); + numSCCs++; +} + +void SCCGraphAnalysis::print(std::ostream& os) const { + const std::string& name = Global::config().get("name"); + std::stringstream ss; + /* Print SCC graph */ + ss << "digraph {" << std::endl; + /* Print nodes of SCC graph */ + for (size_t scc = 0; scc < getNumberOfSCCs(); scc++) { + ss << "\t" << name << "_" << scc << "[label = \""; + ss << join(getInternalRelations(scc), ",\\n", + [](std::ostream& out, const AstRelation* rel) { out << rel->getQualifiedName(); }); + ss << "\" ];" << std::endl; + } + for (size_t scc = 0; scc < getNumberOfSCCs(); scc++) { + for (auto succ : getSuccessorSCCs(scc)) { + ss << "\t" << name << "_" << scc << " -> " << name << "_" << succ << ";" << std::endl; + } + } + ss << "}"; + printHTMLGraph(os, ss.str(), getName()); +} + +} // end of namespace souffle diff --git a/src/ast/analysis/SCCGraph.h b/src/ast/analysis/SCCGraph.h new file mode 100644 index 00000000000..ebd0ff3164f --- /dev/null +++ b/src/ast/analysis/SCCGraph.h @@ -0,0 +1,228 @@ +/* + * Souffle - A Datalog Compiler + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved + * Licensed under the Universal Permissive License v 1.0 as shown at: + * - https://opensource.org/licenses/UPL + * - /licenses/SOUFFLE-UPL.txt + */ + +/************************************************************************ + * + * @file SCCGraph.h + * + * Defines the class to build the precedence graph, + * compute strongly connected components of the precedence graph, and + * build the strongly connected component graph. + * + ***********************************************************************/ + +#pragma once + +#include "GraphUtils.h" +#include "ast/AstRelation.h" +#include "ast/analysis/AstAnalysis.h" +#include "ast/analysis/AstIOType.h" +#include "ast/analysis/PrecedenceGraph.h" +#include +#include +#include +#include +#include +#include +#include + +namespace souffle { + +class AstTranslationUnit; + +/** + * Analysis pass computing the strongly connected component (SCC) graph for the datalog program. + */ +class SCCGraphAnalysis : public AstAnalysis { +public: + static constexpr const char* name = "scc-graph"; + + SCCGraphAnalysis() : AstAnalysis(name) {} + + void run(const AstTranslationUnit& translationUnit) override; + + /** Get the number of SCCs in the graph. */ + size_t getNumberOfSCCs() const { + return sccToRelation.size(); + } + + /** Get the SCC of the given relation. */ + size_t getSCC(const AstRelation* rel) const { + return relationToScc.at(rel); + } + + /** Get all successor SCCs of a given SCC. */ + const std::set& getSuccessorSCCs(const size_t scc) const { + return successors.at(scc); + } + + /** Get all predecessor SCCs of a given SCC. */ + const std::set& getPredecessorSCCs(const size_t scc) const { + return predecessors.at(scc); + } + + /** Get all SCCs containing a successor of a given relation. */ + std::set getSuccessorSCCs(const AstRelation* relation) const { + std::set successorSccs; + const auto scc = relationToScc.at(relation); + for (const auto& successor : precedenceGraph->graph().successors(relation)) { + const auto successorScc = relationToScc.at(successor); + if (successorScc != scc) { + successorSccs.insert(successorScc); + } + } + return successorSccs; + } + + /** Get all SCCs containing a predecessor of a given relation. */ + std::set getPredecessorSCCs(const AstRelation* relation) const { + std::set predecessorSccs; + const auto scc = relationToScc.at(relation); + for (const auto& predecessor : precedenceGraph->graph().predecessors(relation)) { + const auto predecessorScc = relationToScc.at(predecessor); + if (predecessorScc != scc) { + predecessorSccs.insert(predecessorScc); + } + } + return predecessorSccs; + } + + /** Get all internal relations of a given SCC. */ + const std::set& getInternalRelations(const size_t scc) const { + return sccToRelation.at(scc); + } + + /** Get all external output predecessor relations of a given SCC. */ + std::set getExternalOutputPredecessorRelations(const size_t scc) const { + std::set externOutPreds; + for (const auto& relation : getInternalRelations(scc)) { + for (const auto& predecessor : precedenceGraph->graph().predecessors(relation)) { + if (relationToScc.at(predecessor) != scc && ioType->isOutput(predecessor)) { + externOutPreds.insert(predecessor); + } + } + } + return externOutPreds; + } + + /** Get all external non-output predecessor relations of a given SCC. */ + std::set getExternalNonOutputPredecessorRelations(const size_t scc) const { + std::set externNonOutPreds; + for (const auto& relation : getInternalRelations(scc)) { + for (const auto& predecessor : precedenceGraph->graph().predecessors(relation)) { + if (relationToScc.at(predecessor) != scc && !ioType->isOutput(predecessor)) { + externNonOutPreds.insert(predecessor); + } + } + } + return externNonOutPreds; + } + + /** Get all external predecessor relations of a given SCC. */ + std::set getExternalPredecessorRelations(const size_t scc) const { + std::set externPreds; + for (const auto& relation : getInternalRelations(scc)) { + for (const auto& predecessor : precedenceGraph->graph().predecessors(relation)) { + if (relationToScc.at(predecessor) != scc) { + externPreds.insert(predecessor); + } + } + } + return externPreds; + } + + /** Get all internal output relations of a given SCC. */ + std::set getInternalOutputRelations(const size_t scc) const { + std::set internOuts; + for (const auto& relation : getInternalRelations(scc)) { + if (ioType->isOutput(relation)) { + internOuts.insert(relation); + } + } + return internOuts; + } + + /** Get all internal relations of a given SCC with external successors. */ + std::set getInternalRelationsWithExternalSuccessors(const size_t scc) const { + std::set internsWithExternSuccs; + for (const auto& relation : getInternalRelations(scc)) { + for (const auto& successor : precedenceGraph->graph().successors(relation)) { + if (relationToScc.at(successor) != scc) { + internsWithExternSuccs.insert(relation); + break; + } + } + } + return internsWithExternSuccs; + } + + /** Get all internal non-output relations of a given SCC with external successors. */ + std::set getInternalNonOutputRelationsWithExternalSuccessors(const size_t scc) const { + std::set internNonOutsWithExternSuccs; + for (const auto& relation : getInternalRelations(scc)) { + if (!ioType->isOutput(relation)) { + for (const auto& successor : precedenceGraph->graph().successors(relation)) { + if (relationToScc.at(successor) != scc) { + internNonOutsWithExternSuccs.insert(relation); + break; + } + } + } + } + return internNonOutsWithExternSuccs; + } + + /** Get all internal input relations of a given SCC. */ + std::set getInternalInputRelations(const size_t scc) const { + std::set internIns; + for (const auto& relation : getInternalRelations(scc)) { + if (ioType->isInput(relation)) { + internIns.insert(relation); + } + } + return internIns; + } + + /** Return if the given SCC is recursive. */ + bool isRecursive(const size_t scc) const { + const std::set& sccRelations = sccToRelation.at(scc); + if (sccRelations.size() == 1) { + const AstRelation* singleRelation = *sccRelations.begin(); + if (precedenceGraph->graph().predecessors(singleRelation).count(singleRelation) == 0u) { + return false; + } + } + return true; + } + + /** Print the SCC graph. */ + void print(std::ostream& os) const override; + +private: + PrecedenceGraphAnalysis* precedenceGraph = nullptr; + + /** Map from node number to SCC number */ + std::map relationToScc; + + /** Adjacency lists for the SCC graph */ + std::vector> successors; + + /** Predecessor set for the SCC graph */ + std::vector> predecessors; + + /** Relations contained in a SCC */ + std::vector> sccToRelation; + + /** Recursive scR method for computing SCC */ + void scR(const AstRelation* relation, std::map& preOrder, size_t& counter, + std::stack& S, std::stack& P, size_t& numSCCs); + + IOType* ioType = nullptr; +}; + +} // end of namespace souffle diff --git a/src/ast/analysis/TopologicallySortedSCCGraph.cpp b/src/ast/analysis/TopologicallySortedSCCGraph.cpp new file mode 100644 index 00000000000..81341f0da14 --- /dev/null +++ b/src/ast/analysis/TopologicallySortedSCCGraph.cpp @@ -0,0 +1,177 @@ +/* + * Souffle - A Datalog Compiler + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved + * Licensed under the Universal Permissive License v 1.0 as shown at: + * - https://opensource.org/licenses/UPL + * - /licenses/SOUFFLE-UPL.txt + */ + +/************************************************************************ + * + * @file TopologicallySortedSCCGraph.cpp + * + * Implements method of precedence graph to build the precedence graph, + * compute strongly connected components of the precedence graph, and + * build the strongly connected component graph. + * + ***********************************************************************/ + +#include "ast/analysis/TopologicallySortedSCCGraph.h" +#include "ast/AstQualifiedName.h" +#include "ast/AstRelation.h" +#include "ast/AstTranslationUnit.h" +#include "ast/analysis/SCCGraph.h" +#include "utility/StreamUtil.h" +#include +#include +#include + +namespace souffle { + +int TopologicallySortedSCCGraphAnalysis::topologicalOrderingCost( + const std::vector& permutationOfSCCs) const { + // create variables to hold the cost of the current SCC and the permutation as a whole + int costOfSCC = 0; + int costOfPermutation = -1; + // obtain an iterator to the end of the already ordered partition of sccs + auto it_k = permutationOfSCCs.begin() + sccOrder.size(); + // for each of the scc's in the ordering, resetting the cost of the scc to zero on each loop + for (auto it_i = permutationOfSCCs.begin(); it_i != permutationOfSCCs.end(); ++it_i, costOfSCC = 0) { + // if the index of the current scc is after the end of the ordered partition + if (it_i >= it_k) { + // check that the index of all predecessor sccs of are before the index of the current scc + for (auto scc : sccGraph->getPredecessorSCCs(*it_i)) { + if (std::find(permutationOfSCCs.begin(), it_i, scc) == it_i) { + // if not, the sort is not a valid topological sort + return -1; + } + } + } + // otherwise, calculate the cost of the current scc + // as the number of sccs with an index before the current scc + for (auto it_j = permutationOfSCCs.begin(); it_j != it_i; ++it_j) { + // having some successor scc with an index after the current scc + for (auto scc : sccGraph->getSuccessorSCCs(*it_j)) { + if (std::find(permutationOfSCCs.begin(), it_i, scc) == it_i) { + costOfSCC++; + } + } + } + // and if this cost is greater than the maximum recorded cost for the whole permutation so far, + // set the cost of the permutation to it + if (costOfSCC > costOfPermutation) { + costOfPermutation = costOfSCC; + } + } + return costOfPermutation; +} + +void TopologicallySortedSCCGraphAnalysis::computeTopologicalOrdering(size_t scc, std::vector& visited) { + // create a flag to indicate that a successor was visited (by default it hasn't been) + bool found = false; + bool hasUnvisitedSuccessor = false; + bool hasUnvisitedPredecessor = false; + // for each successor of the input scc + const auto& successorsToVisit = sccGraph->getSuccessorSCCs(scc); + for (const auto scc_i : successorsToVisit) { + if (visited[scc_i]) { + continue; + } + hasUnvisitedPredecessor = false; + const auto& successorsPredecessors = sccGraph->getPredecessorSCCs(scc_i); + for (const auto scc_j : successorsPredecessors) { + if (!visited[scc_j]) { + hasUnvisitedPredecessor = true; + break; + } + } + if (!hasUnvisitedPredecessor) { + // give it a temporary marking + visited[scc_i] = true; + // add it to the permanent ordering + sccOrder.push_back(scc_i); + // and use it as a root node in a recursive call to this function + computeTopologicalOrdering(scc_i, visited); + // finally, indicate that a successor has been found for this node + found = true; + } + } + // return at once if no valid successors have been found; as either it has none or they all have a + // better predecessor + if (!found) { + return; + } + hasUnvisitedPredecessor = false; + const auto& predecessors = sccGraph->getPredecessorSCCs(scc); + for (const auto scc_j : predecessors) { + if (!visited[scc_j]) { + hasUnvisitedPredecessor = true; + break; + } + } + hasUnvisitedSuccessor = false; + const auto& successors = sccGraph->getSuccessorSCCs(scc); + for (const auto scc_j : successors) { + if (!visited[scc_j]) { + hasUnvisitedSuccessor = true; + break; + } + } + // otherwise, if more white successors remain for the current scc, use it again as the root node in a + // recursive call to this function + if (hasUnvisitedSuccessor && !hasUnvisitedPredecessor) { + computeTopologicalOrdering(scc, visited); + } +} + +void TopologicallySortedSCCGraphAnalysis::run(const AstTranslationUnit& translationUnit) { + // obtain the scc graph + sccGraph = translationUnit.getAnalysis(); + // clear the list of ordered sccs + sccOrder.clear(); + std::vector visited; + visited.resize(sccGraph->getNumberOfSCCs()); + std::fill(visited.begin(), visited.end(), false); + // generate topological ordering using forwards algorithm (like Khan's algorithm) + // for each of the sccs in the graph + for (size_t scc = 0; scc < sccGraph->getNumberOfSCCs(); ++scc) { + // if that scc has no predecessors + if (sccGraph->getPredecessorSCCs(scc).empty()) { + // put it in the ordering + sccOrder.push_back(scc); + visited[scc] = true; + // if the scc has successors + if (!sccGraph->getSuccessorSCCs(scc).empty()) { + computeTopologicalOrdering(scc, visited); + } + } + } +} + +void TopologicallySortedSCCGraphAnalysis::print(std::ostream& os) const { + os << "--- partial order of strata as list of pairs ---" << std::endl; + for (size_t sccIndex = 0; sccIndex < sccOrder.size(); sccIndex++) { + const auto& successorSccs = sccGraph->getSuccessorSCCs(sccOrder.at(sccIndex)); + // use a self-loop to indicate that an SCC has no successors or predecessors + if (successorSccs.empty() && sccGraph->getPredecessorSCCs(sccOrder.at(sccIndex)).empty()) { + os << sccIndex << " " << sccIndex << std::endl; + continue; + } + for (const auto successorScc : successorSccs) { + const auto successorSccIndex = *std::find(sccOrder.begin(), sccOrder.end(), successorScc); + os << sccIndex << " " << successorSccIndex << std::endl; + } + } + os << "--- total order with relations of each strata ---" << std::endl; + for (size_t i = 0; i < sccOrder.size(); i++) { + os << i << ": ["; + os << join(sccGraph->getInternalRelations(sccOrder[i]), ", ", + [](std::ostream& out, const AstRelation* rel) { out << rel->getQualifiedName(); }); + os << "]" << std::endl; + } + os << std::endl; + os << "--- statistics of topological order ---" << std::endl; + os << "cost: " << topologicalOrderingCost(sccOrder) << std::endl; +} + +} // end of namespace souffle diff --git a/src/ast/analysis/TopologicallySortedSCCGraph.h b/src/ast/analysis/TopologicallySortedSCCGraph.h new file mode 100644 index 00000000000..aa93d4ee5a3 --- /dev/null +++ b/src/ast/analysis/TopologicallySortedSCCGraph.h @@ -0,0 +1,87 @@ +/* + * Souffle - A Datalog Compiler + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved + * Licensed under the Universal Permissive License v 1.0 as shown at: + * - https://opensource.org/licenses/UPL + * - /licenses/SOUFFLE-UPL.txt + */ + +/************************************************************************ + * + * @file TopologicallySortedSCCGraph.h + * + * Defines the class to build the precedence graph, + * compute strongly connected components of the precedence graph, and + * build the strongly connected component graph. + * + ***********************************************************************/ + +#pragma once + +#include "ast/analysis/AstAnalysis.h" +#include +#include +#include +#include +#include +#include +#include +#include + +namespace souffle { + +class AstTranslationUnit; +class SCCGraphAnalysis; + +/** + * Analysis pass computing a topologically sorted strongly connected component (SCC) graph. + */ +class TopologicallySortedSCCGraphAnalysis : public AstAnalysis { +public: + static constexpr const char* name = "topological-scc-graph"; + + TopologicallySortedSCCGraphAnalysis() : AstAnalysis(name) {} + + void run(const AstTranslationUnit& translationUnit) override; + + const std::vector& order() const { + return sccOrder; + } + + size_t sccOfIndex(const size_t index) const { + return sccOrder.at(index); + } + + size_t indexOfScc(const size_t scc) const { + auto it = std::find(sccOrder.begin(), sccOrder.end(), scc); + assert(it != sccOrder.end()); + return (size_t)std::distance(sccOrder.begin(), it); + } + + std::set indexOfScc(const std::set& sccs) const { + std::set indices; + for (const auto scc : sccs) { + indices.insert(indexOfScc(scc)); + } + return indices; + } + + /** Output topologically sorted strongly connected component graph in text format */ + void print(std::ostream& os) const override; + +private: + /** The strongly connected component (SCC) graph. */ + SCCGraphAnalysis* sccGraph = nullptr; + + /** The final topological ordering of the SCCs. */ + std::vector sccOrder; + + /** Calculate the topological ordering cost of a permutation of as of yet unordered SCCs + using the ordered SCCs. Returns -1 if the given vector is not a valid topological ordering. */ + int topologicalOrderingCost(const std::vector& permutationOfSCCs) const; + + /** Recursive component for the forwards algorithm computing the topological ordering of the SCCs. */ + void computeTopologicalOrdering(size_t scc, std::vector& visited); +}; + +} // end of namespace souffle diff --git a/src/ast/transform/AstComponentChecker.cpp b/src/ast/transform/AstComponentChecker.cpp index dd3ff1eb9e2..6e4c476d0cd 100644 --- a/src/ast/transform/AstComponentChecker.cpp +++ b/src/ast/transform/AstComponentChecker.cpp @@ -24,7 +24,6 @@ #include "ast/AstRelation.h" #include "ast/AstTranslationUnit.h" #include "ast/AstType.h" -#include "ast/analysis/ComponentLookupAnalysis.h" #include "utility/StringUtil.h" #include #include diff --git a/src/ast/transform/AstSemanticChecker.cpp b/src/ast/transform/AstSemanticChecker.cpp index 18d61020505..5fcca139bbe 100644 --- a/src/ast/transform/AstSemanticChecker.cpp +++ b/src/ast/transform/AstSemanticChecker.cpp @@ -39,11 +39,14 @@ #include "ast/AstUtils.h" #include "ast/AstVisitor.h" #include "ast/TypeSystem.h" -#include "ast/analysis/AstGroundAnalysis.h" -#include "ast/analysis/AstIOTypeAnalysis.h" -#include "ast/analysis/AstTypeAnalysis.h" -#include "ast/analysis/AstTypeEnvironmentAnalysis.h" +#include "ast/analysis/AstGround.h" +#include "ast/analysis/AstIOType.h" +#include "ast/analysis/AstType.h" +#include "ast/analysis/AstTypeEnvironment.h" #include "ast/analysis/PrecedenceGraph.h" +#include "ast/analysis/RecursiveClauses.h" +#include "ast/analysis/RelationSchedule.h" +#include "ast/analysis/SCCGraph.h" #include "utility/ContainerUtil.h" #include "utility/FunctionalUtil.h" #include "utility/MiscUtil.h" diff --git a/src/ast/transform/ComponentInstantiation.cpp b/src/ast/transform/ComponentInstantiation.cpp index bf7d4832a9f..e7b9508f032 100644 --- a/src/ast/transform/ComponentInstantiation.cpp +++ b/src/ast/transform/ComponentInstantiation.cpp @@ -28,7 +28,6 @@ #include "ast/AstTranslationUnit.h" #include "ast/AstType.h" #include "ast/AstVisitor.h" -#include "ast/analysis/ComponentLookupAnalysis.h" #include "utility/StringUtil.h" #include #include diff --git a/src/ast/transform/IOAttributes.h b/src/ast/transform/IOAttributes.h index fbc644162c3..d9d86299747 100644 --- a/src/ast/transform/IOAttributes.h +++ b/src/ast/transform/IOAttributes.h @@ -18,8 +18,8 @@ #pragma once #include "ast/AstUtils.h" -#include "ast/analysis/AstTypeEnvironmentAnalysis.h" -#include "ast/analysis/AuxArityAnalysis.h" +#include "ast/analysis/AstTypeEnvironment.h" +#include "ast/analysis/AuxArity.h" #include "ast/transform/AstTransformer.h" #include #include diff --git a/src/ast/transform/MagicSet.cpp b/src/ast/transform/MagicSet.cpp index d60eea65d83..a73c8283fa7 100644 --- a/src/ast/transform/MagicSet.cpp +++ b/src/ast/transform/MagicSet.cpp @@ -26,7 +26,7 @@ #include "ast/AstRelation.h" #include "ast/AstTranslationUnit.h" #include "ast/AstUtils.h" -#include "ast/analysis/AstIOTypeAnalysis.h" +#include "ast/analysis/AstIOType.h" #include "utility/ContainerUtil.h" #include "utility/MiscUtil.h" #include "utility/StringUtil.h" diff --git a/src/ast/transform/MaterializeAggregationQueries.cpp b/src/ast/transform/MaterializeAggregationQueries.cpp index fbf13c5acc5..95d150134bb 100644 --- a/src/ast/transform/MaterializeAggregationQueries.cpp +++ b/src/ast/transform/MaterializeAggregationQueries.cpp @@ -28,9 +28,9 @@ #include "ast/AstUtils.h" #include "ast/AstVisitor.h" #include "ast/TypeSystem.h" -#include "ast/analysis/AstGroundAnalysis.h" -#include "ast/analysis/AstTypeAnalysis.h" -#include "ast/analysis/AstTypeEnvironmentAnalysis.h" +#include "ast/analysis/AstGround.h" +#include "ast/analysis/AstType.h" +#include "ast/analysis/AstTypeEnvironment.h" #include "utility/MiscUtil.h" #include "utility/StringUtil.h" #include diff --git a/src/ast/transform/MinimiseProgram.cpp b/src/ast/transform/MinimiseProgram.cpp index 931c47ae94e..741176a61c9 100644 --- a/src/ast/transform/MinimiseProgram.cpp +++ b/src/ast/transform/MinimiseProgram.cpp @@ -25,7 +25,7 @@ #include "ast/AstQualifiedName.h" #include "ast/AstTranslationUnit.h" #include "ast/AstUtils.h" -#include "ast/analysis/AstIOTypeAnalysis.h" +#include "ast/analysis/AstIOType.h" #include "utility/ContainerUtil.h" #include "utility/MiscUtil.h" #include "utility/StringUtil.h" diff --git a/src/ast/transform/PartitionBodyLiterals.cpp b/src/ast/transform/PartitionBodyLiterals.cpp index 4879ef312de..506b7eb2310 100644 --- a/src/ast/transform/PartitionBodyLiterals.cpp +++ b/src/ast/transform/PartitionBodyLiterals.cpp @@ -24,7 +24,6 @@ #include "ast/AstTranslationUnit.h" #include "ast/AstVisitor.h" #include "utility/MiscUtil.h" -#include #include #include #include diff --git a/src/ast/transform/PolymorphicObjects.cpp b/src/ast/transform/PolymorphicObjects.cpp index 33003ba71d9..aee0145c1ec 100644 --- a/src/ast/transform/PolymorphicObjects.cpp +++ b/src/ast/transform/PolymorphicObjects.cpp @@ -23,7 +23,7 @@ #include "ast/AstTranslationUnit.h" #include "ast/AstUtils.h" #include "ast/TypeSystem.h" -#include "ast/analysis/AstTypeAnalysis.h" +#include "ast/analysis/AstType.h" #include "utility/ContainerUtil.h" #include "utility/FunctionalUtil.h" #include diff --git a/src/ast/transform/Provenance.cpp b/src/ast/transform/Provenance.cpp index b96e709290f..3ac1d989481 100644 --- a/src/ast/transform/Provenance.cpp +++ b/src/ast/transform/Provenance.cpp @@ -30,7 +30,6 @@ #include "ast/AstRelation.h" #include "ast/AstTranslationUnit.h" #include "ast/AstUtils.h" -#include "ast/analysis/AuxArityAnalysis.h" #include "utility/ContainerUtil.h" #include "utility/MiscUtil.h" #include "utility/StreamUtil.h" @@ -39,7 +38,6 @@ #include #include #include -#include #include #include #include diff --git a/src/ast/transform/ReduceExistentials.cpp b/src/ast/transform/ReduceExistentials.cpp index 8fbc067bc66..638c0bf7b30 100644 --- a/src/ast/transform/ReduceExistentials.cpp +++ b/src/ast/transform/ReduceExistentials.cpp @@ -26,7 +26,7 @@ #include "ast/AstTranslationUnit.h" #include "ast/AstUtils.h" #include "ast/AstVisitor.h" -#include "ast/analysis/AstIOTypeAnalysis.h" +#include "ast/analysis/AstIOType.h" #include "utility/MiscUtil.h" #include #include diff --git a/src/ast/transform/RemoveEmptyRelations.cpp b/src/ast/transform/RemoveEmptyRelations.cpp index 4a9e20245fb..ba474f57c5a 100644 --- a/src/ast/transform/RemoveEmptyRelations.cpp +++ b/src/ast/transform/RemoveEmptyRelations.cpp @@ -22,7 +22,7 @@ #include "ast/AstTranslationUnit.h" #include "ast/AstUtils.h" #include "ast/AstVisitor.h" -#include "ast/analysis/AstIOTypeAnalysis.h" +#include "ast/analysis/AstIOType.h" #include "utility/MiscUtil.h" #include #include diff --git a/src/ast/transform/RemoveRedundantRelations.cpp b/src/ast/transform/RemoveRedundantRelations.cpp index f1c83dfce65..39cf95b5ea6 100644 --- a/src/ast/transform/RemoveRedundantRelations.cpp +++ b/src/ast/transform/RemoveRedundantRelations.cpp @@ -16,7 +16,7 @@ #include "ast/AstProgram.h" #include "ast/AstRelation.h" #include "ast/AstTranslationUnit.h" -#include "ast/analysis/PrecedenceGraph.h" +#include "ast/analysis/RedundantRelations.h" #include namespace souffle { diff --git a/src/ast/transform/RemoveRelationCopies.cpp b/src/ast/transform/RemoveRelationCopies.cpp index 418991d81d1..fbb9caba193 100644 --- a/src/ast/transform/RemoveRelationCopies.cpp +++ b/src/ast/transform/RemoveRelationCopies.cpp @@ -23,7 +23,7 @@ #include "ast/AstTranslationUnit.h" #include "ast/AstUtils.h" #include "ast/AstVisitor.h" -#include "ast/analysis/AstIOTypeAnalysis.h" +#include "ast/analysis/AstIOType.h" #include "utility/ContainerUtil.h" #include #include diff --git a/src/ast/transform/ResolveAnonymousRecordsAliases.cpp b/src/ast/transform/ResolveAnonymousRecordsAliases.cpp index 58aa6ac73f0..551dff5490c 100644 --- a/src/ast/transform/ResolveAnonymousRecordsAliases.cpp +++ b/src/ast/transform/ResolveAnonymousRecordsAliases.cpp @@ -22,8 +22,8 @@ #include "ast/AstProgram.h" #include "ast/AstTranslationUnit.h" #include "ast/TypeSystem.h" -#include "ast/analysis/AstGroundAnalysis.h" -#include "ast/analysis/AstTypeAnalysis.h" +#include "ast/analysis/AstGround.h" +#include "ast/analysis/AstType.h" #include "utility/MiscUtil.h" #include #include diff --git a/src/interpreter/InterpreterPreamble.h b/src/interpreter/InterpreterPreamble.h index 40e621bd4b0..895b3f6d835 100644 --- a/src/interpreter/InterpreterPreamble.h +++ b/src/interpreter/InterpreterPreamble.h @@ -8,7 +8,7 @@ /************************************************************************ * - * @file InterpreterPreamble + * @file InterpreterPreamble.h * * Declares the InterpreterPreamble class. * Each Query operation has an InterpreterPreamble assoicated with it. diff --git a/src/main.cpp b/src/main.cpp index a2eff15c2e8..b3499aebf1b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -24,7 +24,7 @@ #include "ast/AstNode.h" #include "ast/AstProgram.h" #include "ast/AstTranslationUnit.h" -#include "ast/analysis/AstTypeAnalysis.h" +#include "ast/analysis/AstType.h" #include "ast/analysis/PrecedenceGraph.h" #include "ast/transform/AstComponentChecker.h" #include "ast/transform/AstPragmaChecker.h" diff --git a/src/ram/analysis/RamIndexAnalysis.cpp b/src/ram/analysis/RamIndexAnalysis.cpp index d6d50f05f56..700d2cc4cb8 100644 --- a/src/ram/analysis/RamIndexAnalysis.cpp +++ b/src/ram/analysis/RamIndexAnalysis.cpp @@ -8,7 +8,7 @@ /************************************************************************ * - * @file IndexAnalysis.cpp + * @file RamIndexAnalysis.cpp * * Computes indexes for relations in a translation unit * diff --git a/src/tests/ast_transformers_test.cpp b/src/tests/ast_transformers_test.cpp index 98423de122e..886d7fde38b 100644 --- a/src/tests/ast_transformers_test.cpp +++ b/src/tests/ast_transformers_test.cpp @@ -29,7 +29,7 @@ #include "ast/AstQualifiedName.h" #include "ast/AstTranslationUnit.h" #include "ast/AstUtils.h" -#include "ast/analysis/AstGroundAnalysis.h" +#include "ast/analysis/AstGround.h" #include "ast/transform/MinimiseProgram.h" #include "ast/transform/RemoveRelationCopies.h" #include "ast/transform/ResolveAliases.h" diff --git a/src/tests/ast_utils_test.cpp b/src/tests/ast_utils_test.cpp index 48374713317..94ec20498cf 100644 --- a/src/tests/ast_utils_test.cpp +++ b/src/tests/ast_utils_test.cpp @@ -29,7 +29,7 @@ #include "ast/AstQualifiedName.h" #include "ast/AstTranslationUnit.h" #include "ast/AstUtils.h" -#include "ast/analysis/AstGroundAnalysis.h" +#include "ast/analysis/AstGround.h" #include "utility/StringUtil.h" #include #include diff --git a/src/tests/brie_test.cpp b/src/tests/brie_test.cpp index 179c79b3e09..4cb21ea9e9d 100644 --- a/src/tests/brie_test.cpp +++ b/src/tests/brie_test.cpp @@ -8,7 +8,7 @@ /************************************************************************ * - * @file brie_test.h + * @file brie_test.cpp * * A test case testing the trie implementation. * diff --git a/src/tests/btree_multiset_test.cpp b/src/tests/btree_multiset_test.cpp index ae72b99cc10..2df9aa8bd3b 100644 --- a/src/tests/btree_multiset_test.cpp +++ b/src/tests/btree_multiset_test.cpp @@ -8,7 +8,7 @@ /************************************************************************ * - * @file btree_multiset_test.h + * @file btree_multiset_test.cpp * * A test case testing the B-trees utilization as multisets. * diff --git a/src/tests/btree_set_test.cpp b/src/tests/btree_set_test.cpp index 1cd6158b530..45c4effced2 100644 --- a/src/tests/btree_set_test.cpp +++ b/src/tests/btree_set_test.cpp @@ -8,7 +8,7 @@ /************************************************************************ * - * @file btree_set_test.h + * @file btree_set_test.cpp * * A test case testing the B-trees utilization as sets. * diff --git a/src/tests/compiled_tuple_test.cpp b/src/tests/compiled_tuple_test.cpp index 3d589d8ce26..25b5c05cf40 100644 --- a/src/tests/compiled_tuple_test.cpp +++ b/src/tests/compiled_tuple_test.cpp @@ -8,7 +8,7 @@ /************************************************************************ * - * @file compiled_test.h + * @file compiled_tuple_test.cpp * * Test cases for the RAM tuple data structure. * diff --git a/src/tests/constraints_test.cpp b/src/tests/constraints_test.cpp index 842d145ddac..88e1976acdc 100644 --- a/src/tests/constraints_test.cpp +++ b/src/tests/constraints_test.cpp @@ -8,7 +8,7 @@ /************************************************************************ * - * @file type_system_test.h + * @file constraints_test.cpp * * Tests souffle's type system operations. * diff --git a/src/tests/graph_utils_test.cpp b/src/tests/graph_utils_test.cpp index dc56ab3d03f..c8766b123b4 100644 --- a/src/tests/graph_utils_test.cpp +++ b/src/tests/graph_utils_test.cpp @@ -8,7 +8,7 @@ /************************************************************************ * - * @file type_system_test.h + * @file graph_utils_test.cpp * * Tests souffle's type system operations. * diff --git a/src/tests/interpreter_relation_test.cpp b/src/tests/interpreter_relation_test.cpp index 26e206454aa..e25e241dd48 100644 --- a/src/tests/interpreter_relation_test.cpp +++ b/src/tests/interpreter_relation_test.cpp @@ -8,7 +8,7 @@ /************************************************************************ * - * @file interpreter_relation_test.h + * @file interpreter_relation_test.cpp * * Tests InterpreterRelInterface * diff --git a/src/tests/matching_test.cpp b/src/tests/matching_test.cpp index d586bd8214b..5fac8772b64 100644 --- a/src/tests/matching_test.cpp +++ b/src/tests/matching_test.cpp @@ -8,7 +8,7 @@ /************************************************************************ * - * @file matching_test.h + * @file matching_test.cpp * * Test cases for the computation of optimal indices. * diff --git a/src/tests/max_matching_test.cpp b/src/tests/max_matching_test.cpp index 9391d2f9243..b61cbce9c67 100644 --- a/src/tests/max_matching_test.cpp +++ b/src/tests/max_matching_test.cpp @@ -8,7 +8,7 @@ /************************************************************************ * - * @file max_matching_test.h + * @file max_matching_test.cpp * * Test cases for the computation of maximum matching. * diff --git a/src/tests/parallel_utils_test.cpp b/src/tests/parallel_utils_test.cpp index 44f451ee107..2c2343c3330 100644 --- a/src/tests/parallel_utils_test.cpp +++ b/src/tests/parallel_utils_test.cpp @@ -8,7 +8,7 @@ /************************************************************************ * - * @file btree_set_test.h + * @file parallel_utils_test.cpp * * A test case testing the B-trees utilization as sets. * diff --git a/src/tests/profile_util_test.cpp b/src/tests/profile_util_test.cpp index 6f975b89a66..28c1915b28a 100644 --- a/src/tests/profile_util_test.cpp +++ b/src/tests/profile_util_test.cpp @@ -8,7 +8,7 @@ /************************************************************************ * - * @file profile_util_test.h + * @file profile_util_test.cpp * * Test cases for the profile utilities. * diff --git a/src/tests/ram_relation_test.cpp b/src/tests/ram_relation_test.cpp index 9fcd92930fa..faccb9022e1 100644 --- a/src/tests/ram_relation_test.cpp +++ b/src/tests/ram_relation_test.cpp @@ -8,7 +8,7 @@ /************************************************************************ * - * @file ram_arithmetic_test.cpp + * @file ram_relation_test.cpp * * Tests arithmetic evaluation by the Interpreter. * diff --git a/src/tests/symbol_table_test.cpp b/src/tests/symbol_table_test.cpp index 51a194530ed..4fc7b288e89 100644 --- a/src/tests/symbol_table_test.cpp +++ b/src/tests/symbol_table_test.cpp @@ -8,7 +8,7 @@ /************************************************************************ * - * @file symbol_table_test.h + * @file symbol_table_test.cpp * * Tests souffle's symbol table. * diff --git a/src/tests/table_test.cpp b/src/tests/table_test.cpp index 20423523d0e..ee0d20d4815 100644 --- a/src/tests/table_test.cpp +++ b/src/tests/table_test.cpp @@ -8,7 +8,7 @@ /************************************************************************ * - * @file table_test.h + * @file table_test.cpp * * Test cases for the Table data structure. * diff --git a/src/tests/type_system_test.cpp b/src/tests/type_system_test.cpp index ef16ea05353..096c9b7fc45 100644 --- a/src/tests/type_system_test.cpp +++ b/src/tests/type_system_test.cpp @@ -8,7 +8,7 @@ /************************************************************************ * - * @file type_system_test.h + * @file type_system_test.cpp * * Tests souffle's type system operations. *