souffle  2.0.2-371-g6315b36
AstToRamTranslator.cpp
Go to the documentation of this file.
1 /*
2  * Souffle - A Datalog Compiler
3  * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved
4  * Licensed under the Universal Permissive License v 1.0 as shown at:
5  * - https://opensource.org/licenses/UPL
6  * - <souffle root>/licenses/SOUFFLE-UPL.txt
7  */
8 
9 /************************************************************************
10  *
11  * @file AstToRamTranslator.cpp
12  *
13  * Translator from AST to RAM structures.
14  *
15  ***********************************************************************/
16 
18 #include "Global.h"
19 #include "LogStatement.h"
20 #include "ast/Aggregator.h"
21 #include "ast/Argument.h"
22 #include "ast/Atom.h"
23 #include "ast/BinaryConstraint.h"
24 #include "ast/BranchInit.h"
25 #include "ast/Clause.h"
26 #include "ast/Constant.h"
27 #include "ast/Constraint.h"
28 #include "ast/Counter.h"
29 #include "ast/Directive.h"
30 #include "ast/Functor.h"
31 #include "ast/IntrinsicFunctor.h"
32 #include "ast/Literal.h"
33 #include "ast/Negation.h"
34 #include "ast/NilConstant.h"
35 #include "ast/Node.h"
36 #include "ast/NumericConstant.h"
37 #include "ast/Program.h"
38 #include "ast/QualifiedName.h"
39 #include "ast/RecordInit.h"
40 #include "ast/Relation.h"
41 #include "ast/StringConstant.h"
42 #include "ast/SubroutineArgument.h"
43 #include "ast/TranslationUnit.h"
44 #include "ast/UnnamedVariable.h"
45 #include "ast/UserDefinedFunctor.h"
46 #include "ast/Variable.h"
47 #include "ast/analysis/AuxArity.h"
48 #include "ast/analysis/Functor.h"
49 #include "ast/analysis/IOType.h"
53 #include "ast/analysis/SCCGraph.h"
59 #include "ast/utility/NodeMapper.h"
60 #include "ast/utility/SipsMetric.h"
61 #include "ast/utility/Utils.h"
62 #include "ast/utility/Visitor.h"
64 #include "ast2ram/Location.h"
66 #include "ast2ram/ValueIndex.h"
67 #include "parser/SrcLocation.h"
68 #include "ram/AutoIncrement.h"
69 #include "ram/Call.h"
70 #include "ram/Clear.h"
71 #include "ram/Condition.h"
72 #include "ram/Conjunction.h"
73 #include "ram/Constraint.h"
74 #include "ram/DebugInfo.h"
75 #include "ram/EmptinessCheck.h"
76 #include "ram/ExistenceCheck.h"
77 #include "ram/Exit.h"
78 #include "ram/Expression.h"
79 #include "ram/Extend.h"
80 #include "ram/Filter.h"
81 #include "ram/FloatConstant.h"
82 #include "ram/IO.h"
83 #include "ram/IntrinsicOperator.h"
84 #include "ram/LogRelationTimer.h"
85 #include "ram/LogSize.h"
86 #include "ram/LogTimer.h"
87 #include "ram/Loop.h"
88 #include "ram/Negation.h"
89 #include "ram/PackRecord.h"
90 #include "ram/Parallel.h"
91 #include "ram/Program.h"
92 #include "ram/Project.h"
94 #include "ram/Query.h"
95 #include "ram/Relation.h"
96 #include "ram/RelationSize.h"
97 #include "ram/Scan.h"
98 #include "ram/Sequence.h"
99 #include "ram/SignedConstant.h"
100 #include "ram/Statement.h"
101 #include "ram/SubroutineArgument.h"
102 #include "ram/SubroutineReturn.h"
103 #include "ram/Swap.h"
104 #include "ram/TranslationUnit.h"
105 #include "ram/TupleElement.h"
106 #include "ram/UndefValue.h"
107 #include "ram/UnsignedConstant.h"
108 #include "ram/UserDefinedOperator.h"
109 #include "ram/utility/Utils.h"
110 #include "reports/DebugReport.h"
111 #include "reports/ErrorReport.h"
113 #include "souffle/SymbolTable.h"
114 #include "souffle/TypeAttribute.h"
118 #include <algorithm>
119 #include <cassert>
120 #include <chrono>
121 #include <cstddef>
122 #include <iterator>
123 #include <map>
124 #include <memory>
125 #include <optional>
126 #include <set>
127 #include <sstream>
128 #include <string>
129 #include <utility>
130 #include <vector>
131 
132 namespace souffle::ast2ram {
133 
136 
137 /** append statement to a list of statements */
138 inline void appendStmt(VecOwn<ram::Statement>& stmtList, Own<ram::Statement> stmt) {
139  if (stmt) {
140  stmtList.push_back(std::move(stmt));
141  }
142 }
143 
145  return mk<ram::TupleElement>(loc.identifier, loc.element);
146 }
147 
148 size_t AstToRamTranslator::getEvaluationArity(const ast::Atom* atom) const {
149  if (atom->getQualifiedName().toString().find("@delta_") == 0) {
150  const ast::QualifiedName& originalRel =
151  ast::QualifiedName(atom->getQualifiedName().toString().substr(7));
152  return auxArityAnalysis->getArity(getRelation(*program, originalRel));
153  } else if (atom->getQualifiedName().toString().find("@new_") == 0) {
154  const ast::QualifiedName& originalRel =
155  ast::QualifiedName(atom->getQualifiedName().toString().substr(5));
156  return auxArityAnalysis->getArity(getRelation(*program, originalRel));
157  } else if (atom->getQualifiedName().toString().find("@info_") == 0) {
158  return 0;
159  } else {
160  return auxArityAnalysis->getArity(atom);
161  }
162 }
163 
164 std::vector<std::map<std::string, std::string>> AstToRamTranslator::getInputDirectives(
165  const ast::Relation* rel) {
166  std::vector<std::map<std::string, std::string>> inputDirectives;
167 
168  for (const auto* load : program->getDirectives()) {
169  if (load->getQualifiedName() != rel->getQualifiedName() ||
170  load->getType() != ast::DirectiveType::input) {
171  continue;
172  }
173 
174  std::map<std::string, std::string> directives;
175  for (const auto& currentPair : load->getParameters()) {
176  directives.insert(std::make_pair(currentPair.first, unescape(currentPair.second)));
177  }
178  inputDirectives.push_back(directives);
179  }
180 
181  if (inputDirectives.empty()) {
182  inputDirectives.emplace_back();
183  }
184 
185  return inputDirectives;
186 }
187 
188 std::vector<std::map<std::string, std::string>> AstToRamTranslator::getOutputDirectives(
189  const ast::Relation* rel) {
190  std::vector<std::map<std::string, std::string>> outputDirectives;
191 
192  for (const auto* store : program->getDirectives()) {
193  if (store->getQualifiedName() != rel->getQualifiedName() ||
194  (store->getType() != ast::DirectiveType::printsize &&
195  store->getType() != ast::DirectiveType::output)) {
196  continue;
197  }
198 
199  std::map<std::string, std::string> directives;
200  for (const auto& currentPair : store->getParameters()) {
201  directives.insert(std::make_pair(currentPair.first, unescape(currentPair.second)));
202  }
203  outputDirectives.push_back(directives);
204  }
205 
206  if (outputDirectives.empty()) {
207  outputDirectives.emplace_back();
208  }
209 
210  return outputDirectives;
211 }
212 
213 std::string AstToRamTranslator::translateRelation(const ast::Atom* atom) {
214  return getRelationName(atom->getQualifiedName());
215 }
216 
218  const ast::Relation* rel, const std::string relationNamePrefix) {
219  return relationNamePrefix + getRelationName(rel->getQualifiedName());
220 }
221 
223  return translateRelation(rel, "@delta_");
224 }
225 
227  return translateRelation(rel, "@new_");
228 }
229 
231  if (arg == nullptr) {
232  return nullptr;
233  }
234 
235  class ValueTranslator : public ast::Visitor<Own<ram::Expression>> {
236  AstToRamTranslator& translator;
237  const ValueIndex& index;
239 
240  public:
241  ValueTranslator(AstToRamTranslator& translator, const ValueIndex& index,
243  : translator(translator), index(index), polyAnalysis(polyAnalysis) {}
244 
245  Own<ram::Expression> visitVariable(const ast::Variable& var) override {
246  if (!index.isDefined(var)) fatal("variable `%s` is not grounded", var);
247  return makeRamTupleElement(index.getDefinitionPoint(var));
248  }
249 
250  Own<ram::Expression> visitUnnamedVariable(const ast::UnnamedVariable&) override {
251  return mk<ram::UndefValue>();
252  }
253 
254  Own<ram::Expression> visitNumericConstant(const ast::NumericConstant& c) override {
255  assert(c.getFinalType().has_value() && "constant should have valid type");
256  switch (c.getFinalType().value()) {
258  return mk<ram::SignedConstant>(RamSignedFromString(c.getConstant(), nullptr, 0));
260  return mk<ram::UnsignedConstant>(RamUnsignedFromString(c.getConstant(), nullptr, 0));
262  return mk<ram::FloatConstant>(RamFloatFromString(c.getConstant()));
263  }
264 
265  fatal("unexpected numeric constant type");
266  }
267 
268  Own<ram::Expression> visitStringConstant(const ast::StringConstant& c) override {
269  return mk<ram::SignedConstant>(translator.getSymbolTable().lookup(c.getConstant()));
270  }
271 
272  Own<ram::Expression> visitNilConstant(const ast::NilConstant&) override {
273  return mk<ram::SignedConstant>(0);
274  }
275 
276  Own<ram::Expression> visitTypeCast(const ast::TypeCast& typeCast) override {
277  return translator.translateValue(typeCast.getValue(), index);
278  }
279 
280  Own<ram::Expression> visitIntrinsicFunctor(const ast::IntrinsicFunctor& inf) override {
281  VecOwn<ram::Expression> values;
282  for (const auto& cur : inf.getArguments()) {
283  values.push_back(translator.translateValue(cur, index));
284  }
285 
287  return translator.makeRamTupleElement(index.getGeneratorLoc(inf));
288  } else {
289  return mk<ram::IntrinsicOperator>(inf.getFinalOpType().value(), std::move(values));
290  }
291  }
292 
293  Own<ram::Expression> visitUserDefinedFunctor(const ast::UserDefinedFunctor& udf) override {
294  VecOwn<ram::Expression> values;
295  for (const auto& cur : udf.getArguments()) {
296  values.push_back(translator.translateValue(cur, index));
297  }
298  auto returnType = translator.functorAnalysis->getReturnType(&udf);
299  auto argTypes = translator.functorAnalysis->getArgTypes(udf);
300  return mk<ram::UserDefinedOperator>(udf.getName(), argTypes, returnType,
301  translator.functorAnalysis->isStateful(&udf), std::move(values));
302  }
303 
304  Own<ram::Expression> visitCounter(const ast::Counter&) override {
305  return mk<ram::AutoIncrement>();
306  }
307 
308  Own<ram::Expression> visitRecordInit(const ast::RecordInit& init) override {
309  VecOwn<ram::Expression> values;
310  for (const auto& cur : init.getArguments()) {
311  values.push_back(translator.translateValue(cur, index));
312  }
313  return mk<ram::PackRecord>(std::move(values));
314  }
315 
316  Own<ram::Expression> visitAggregator(const ast::Aggregator& agg) override {
317  // here we look up the location the aggregation result gets bound
318  return translator.makeRamTupleElement(index.getGeneratorLoc(agg));
319  }
320 
321  Own<ram::Expression> visitSubroutineArgument(const ast::SubroutineArgument& subArg) override {
322  return mk<ram::SubroutineArgument>(subArg.getNumber());
323  }
324  };
325 
326  return ValueTranslator(*this, index, polyAnalysis)(*arg);
327 }
328 
329 SymbolTable& AstToRamTranslator::getSymbolTable() {
330  static SymbolTable symbolTable;
331  return symbolTable;
332 }
333 
334 Own<ram::Condition> AstToRamTranslator::translateConstraint(
335  const ast::Literal* lit, const ValueIndex& index) {
336  class ConstraintTranslator : public ast::Visitor<Own<ram::Condition>> {
337  AstToRamTranslator& translator;
338  const ValueIndex& index;
340 
341  public:
342  ConstraintTranslator(AstToRamTranslator& translator, const ValueIndex& index,
344  : translator(translator), index(index), polyAnalysis(polyAnalysis) {}
345 
346  /** for atoms */
347  Own<ram::Condition> visitAtom(const ast::Atom&) override {
348  return nullptr; // covered already within the scan/lookup generation step
349  }
350 
351  /** for binary relations */
352  Own<ram::Condition> visitBinaryConstraint(const ast::BinaryConstraint& binRel) override {
353  assert(binRel.getFinalType().has_value() && "binary constraint has unset type");
354  auto valLHS = translator.translateValue(binRel.getLHS(), index);
355  auto valRHS = translator.translateValue(binRel.getRHS(), index);
356  return mk<ram::Constraint>(binRel.getFinalType().value(), std::move(valLHS), std::move(valRHS));
357  }
358 
359  /** for provenance negation */
360  Own<ram::Condition> visitProvenanceNegation(const ast::ProvenanceNegation& neg) override {
361  const auto* atom = neg.getAtom();
362  size_t auxiliaryArity = translator.getEvaluationArity(atom);
363  assert(auxiliaryArity <= atom->getArity() && "auxiliary arity out of bounds");
364  size_t arity = atom->getArity() - auxiliaryArity;
365  VecOwn<ram::Expression> values;
366 
367  auto args = atom->getArguments();
368  for (size_t i = 0; i < arity; i++) {
369  values.push_back(translator.translateValue(args[i], index));
370  }
371  // we don't care about the provenance columns when doing the existence check
372  if (Global::config().has("provenance")) {
373  // undefined value for rule number
374  values.push_back(mk<ram::UndefValue>());
375  // add the height annotation for provenanceNotExists
376  for (size_t height = 1; height < auxiliaryArity; height++) {
377  values.push_back(translator.translateValue(args[arity + height], index));
378  }
379  }
380  return mk<ram::Negation>(
381  mk<ram::ProvenanceExistenceCheck>(translator.translateRelation(atom), std::move(values)));
382  }
383 
384  /** for negations */
385  Own<ram::Condition> visitNegation(const ast::Negation& neg) override {
386  const auto* atom = neg.getAtom();
387  size_t auxiliaryArity = translator.getEvaluationArity(atom);
388  assert(auxiliaryArity <= atom->getArity() && "auxiliary arity out of bounds");
389  size_t arity = atom->getArity() - auxiliaryArity;
390 
391  if (arity == 0) {
392  // for a nullary, negation is a simple emptiness check
393  return mk<ram::EmptinessCheck>(translator.translateRelation(atom));
394  }
395 
396  // else, we construct the atom and create a negation
397  VecOwn<ram::Expression> values;
398  auto args = atom->getArguments();
399  for (size_t i = 0; i < arity; i++) {
400  values.push_back(translator.translateValue(args[i], index));
401  }
402  for (size_t i = 0; i < auxiliaryArity; i++) {
403  values.push_back(mk<ram::UndefValue>());
404  }
405  return mk<ram::Negation>(
406  mk<ram::ExistenceCheck>(translator.translateRelation(atom), std::move(values)));
407  }
408  };
409  return ConstraintTranslator(*this, index, polyAnalysis)(*lit);
410 }
411 
412 RamDomain AstToRamTranslator::getConstantRamRepresentation(const ast::Constant& constant) {
413  if (auto strConstant = dynamic_cast<const ast::StringConstant*>(&constant)) {
414  return getSymbolTable().lookup(strConstant->getConstant());
415  } else if (isA<ast::NilConstant>(&constant)) {
416  return 0;
417  } else if (auto* numConstant = dynamic_cast<const ast::NumericConstant*>(&constant)) {
418  assert(numConstant->getFinalType().has_value() && "constant should have valid type");
419  switch (numConstant->getFinalType().value()) {
421  return RamSignedFromString(numConstant->getConstant(), nullptr, 0);
423  return RamUnsignedFromString(numConstant->getConstant(), nullptr, 0);
424  case ast::NumericConstant::Type::Float: return RamFloatFromString(numConstant->getConstant());
425  }
426  }
427 
428  fatal("unaccounted-for constant");
429 }
430 
431 Own<ram::Expression> AstToRamTranslator::translateConstant(ast::Constant const& c) {
432  auto const rawConstant = getConstantRamRepresentation(c);
433 
434  if (auto* const c_num = dynamic_cast<const ast::NumericConstant*>(&c)) {
435  switch (c_num->getFinalType().value()) {
436  case ast::NumericConstant::Type::Int: return mk<ram::SignedConstant>(rawConstant);
437  case ast::NumericConstant::Type::Uint: return mk<ram::UnsignedConstant>(rawConstant);
438  case ast::NumericConstant::Type::Float: return mk<ram::FloatConstant>(rawConstant);
439  }
440  }
441 
442  return mk<ram::SignedConstant>(rawConstant);
443 }
444 
445 /** generate RAM code for a non-recursive relation */
447  const ast::Relation& rel, const ast::analysis::RecursiveClausesAnalysis* recursiveClauses) {
448  /* start with an empty sequence */
449  VecOwn<ram::Statement> res;
450 
451  std::string relName = translateRelation(&rel);
452 
453  /* iterate over all clauses that belong to the relation */
454  for (ast::Clause* clause : getClauses(*program, rel)) {
455  // skip recursive rules
456  if (recursiveClauses->recursive(clause)) {
457  continue;
458  }
459 
460  // translate clause
461  Own<ram::Statement> rule = ClauseTranslator(*this).translateClause(*clause, *clause);
462 
463  // add logging
464  if (Global::config().has("profile")) {
465  const std::string& relationName = toString(rel.getQualifiedName());
466  const SrcLocation& srcLocation = clause->getSrcLoc();
467  const std::string clauseText = stringify(toString(*clause));
468  const std::string logTimerStatement =
469  LogStatement::tNonrecursiveRule(relationName, srcLocation, clauseText);
470  const std::string logSizeStatement =
471  LogStatement::nNonrecursiveRule(relationName, srcLocation, clauseText);
472  rule = mk<ram::LogRelationTimer>(std::move(rule), logTimerStatement, relName);
473  }
474 
475  // add debug info
476  std::ostringstream ds;
477  ds << toString(*clause) << "\nin file ";
478  ds << clause->getSrcLoc();
479  rule = mk<ram::DebugInfo>(std::move(rule), ds.str());
480 
481  // add rule to result
482  appendStmt(res, std::move(rule));
483  }
484 
485  // add logging for entire relation
486  if (Global::config().has("profile")) {
487  const std::string& relationName = toString(rel.getQualifiedName());
488  const SrcLocation& srcLocation = rel.getSrcLoc();
489  const std::string logSizeStatement = LogStatement::nNonrecursiveRelation(relationName, srcLocation);
490 
491  // add timer if we did any work
492  if (!res.empty()) {
493  const std::string logTimerStatement =
494  LogStatement::tNonrecursiveRelation(relationName, srcLocation);
495  auto newStmt =
496  mk<ram::LogRelationTimer>(mk<ram::Sequence>(std::move(res)), logTimerStatement, relName);
497  res.clear();
498  appendStmt(res, std::move(newStmt));
499  } else {
500  // add table size printer
501  appendStmt(res, mk<ram::LogSize>(relName, logSizeStatement));
502  }
503  }
504 
505  // done
506  return mk<ram::Sequence>(std::move(res));
507 }
508 
509 /**
510  * A utility function assigning names to unnamed variables such that enclosing
511  * constructs may be cloned without losing the variable-identity.
512  */
513 void AstToRamTranslator::nameUnnamedVariables(ast::Clause* clause) {
514  // the node mapper conducting the actual renaming
515  struct Instantiator : public ast::NodeMapper {
516  mutable int counter = 0;
517 
518  Instantiator() = default;
519 
520  Own<ast::Node> operator()(Own<ast::Node> node) const override {
521  // apply recursive
522  node->apply(*this);
523 
524  // replace unknown variables
525  if (dynamic_cast<ast::UnnamedVariable*>(node.get()) != nullptr) {
526  auto name = " _unnamed_var" + toString(++counter);
527  return mk<ast::Variable>(name);
528  }
529 
530  // otherwise nothing
531  return node;
532  }
533  };
534 
535  // name all variables in the atoms
536  Instantiator init;
537  for (auto& atom : ast::getBodyLiterals<ast::Atom>(*clause)) {
538  atom->apply(init);
539  }
540 }
541 
542 /** converts the given relation identifier into a relation name */
543 std::string AstToRamTranslator::getRelationName(const ast::QualifiedName& id) {
544  return toString(join(id.getQualifiers(), "."));
545 }
546 
547 /** generate RAM code for recursive relations in a strongly-connected component */
548 Own<ram::Statement> AstToRamTranslator::translateRecursiveRelation(const std::set<const ast::Relation*>& scc,
549  const ast::analysis::RecursiveClausesAnalysis* recursiveClauses) {
550  // initialize sections
551  VecOwn<ram::Statement> preamble;
552  VecOwn<ram::Statement> updateTable;
553  VecOwn<ram::Statement> postamble;
554 
555  auto genMerge = [&](const ast::Relation* rel, const std::string& destRel,
556  const std::string& srcRel) -> Own<ram::Statement> {
558  if (rel->getArity() == 0) {
559  return mk<ram::Query>(mk<ram::Filter>(mk<ram::Negation>(mk<ram::EmptinessCheck>(srcRel)),
560  mk<ram::Project>(destRel, std::move(values))));
561  }
562  for (std::size_t i = 0; i < rel->getArity(); i++) {
563  values.push_back(mk<ram::TupleElement>(0, i));
564  }
565  auto stmt = mk<ram::Query>(mk<ram::Scan>(srcRel, 0, mk<ram::Project>(destRel, std::move(values))));
566  if (rel->getRepresentation() == RelationRepresentation::EQREL) {
567  return mk<ram::Sequence>(mk<ram::Extend>(destRel, srcRel), std::move(stmt));
568  }
569  return stmt;
570  };
571 
572  // --- create preamble ---
573 
574  /* Compute non-recursive clauses for relations in scc and push
575  the results in their delta tables. */
576  for (const ast::Relation* rel : scc) {
577  /* create update statements for fixpoint (even iteration) */
578  Own<ram::Statement> updateRelTable =
579  mk<ram::Sequence>(genMerge(rel, translateRelation(rel), translateNewRelation(rel)),
581  mk<ram::Clear>(translateNewRelation(rel)));
582 
583  /* measure update time for each relation */
584  if (Global::config().has("profile")) {
585  updateRelTable = mk<ram::LogRelationTimer>(std::move(updateRelTable),
586  LogStatement::cRecursiveRelation(toString(rel->getQualifiedName()), rel->getSrcLoc()),
588  }
589 
590  /* drop temporary tables after recursion */
591  appendStmt(postamble, mk<ram::Clear>(translateDeltaRelation(rel)));
592  appendStmt(postamble, mk<ram::Clear>(translateNewRelation(rel)));
593 
594  /* Generate code for non-recursive part of relation */
595  /* Generate merge operation for temp tables */
596  appendStmt(preamble, translateNonRecursiveRelation(*rel, recursiveClauses));
598 
599  /* Add update operations of relations to parallel statements */
600  appendStmt(updateTable, std::move(updateRelTable));
601  }
602 
603  // --- build main loop ---
604 
605  VecOwn<ram::Statement> loopSeq;
606 
607  // create a utility to check SCC membership
608  auto isInSameSCC = [&](const ast::Relation* rel) {
609  return std::find(scc.begin(), scc.end(), rel) != scc.end();
610  };
611 
612  /* Compute temp for the current tables */
613  for (const ast::Relation* rel : scc) {
614  VecOwn<ram::Statement> loopRelSeq;
615 
616  /* Find clauses for relation rel */
617  for (const auto& cl : getClauses(*program, *rel)) {
618  // skip non-recursive clauses
619  if (!recursiveClauses->recursive(cl)) {
620  continue;
621  }
622 
623  // each recursive rule results in several operations
624  int version = 0;
625  const auto& atoms = ast::getBodyLiterals<ast::Atom>(*cl);
626  for (size_t j = 0; j < atoms.size(); ++j) {
627  const ast::Atom* atom = atoms[j];
628  const ast::Relation* atomRelation = getAtomRelation(atom, program);
629 
630  // only interested in atoms within the same SCC
631  if (!isInSameSCC(atomRelation)) {
632  continue;
633  }
634 
635  // modify the processed rule to use delta relation and write to new relation
636  Own<ast::Clause> r1(cl->clone());
637  r1->getHead()->setQualifiedName(translateNewRelation(rel));
638  ast::getBodyLiterals<ast::Atom>(*r1)[j]->setQualifiedName(
639  translateDeltaRelation(atomRelation));
640  if (Global::config().has("provenance")) {
641  r1->addToBody(mk<ast::ProvenanceNegation>(souffle::clone(cl->getHead())));
642  } else {
643  if (r1->getHead()->getArity() > 0) {
644  r1->addToBody(mk<ast::Negation>(souffle::clone(cl->getHead())));
645  }
646  }
647 
648  // replace wildcards with variables (reduces indices when wildcards are used in recursive
649  // atoms)
650  nameUnnamedVariables(r1.get());
651 
652  // reduce R to P ...
653  for (size_t k = j + 1; k < atoms.size(); k++) {
654  if (isInSameSCC(getAtomRelation(atoms[k], program))) {
655  auto cur = souffle::clone(ast::getBodyLiterals<ast::Atom>(*r1)[k]);
656  cur->setQualifiedName(translateDeltaRelation(getAtomRelation(atoms[k], program)));
657  r1->addToBody(mk<ast::Negation>(std::move(cur)));
658  }
659  }
660 
661  Own<ram::Statement> rule = ClauseTranslator(*this).translateClause(*r1, *cl, version);
662 
663  /* add logging */
664  if (Global::config().has("profile")) {
665  const std::string& relationName = toString(rel->getQualifiedName());
666  const SrcLocation& srcLocation = cl->getSrcLoc();
667  const std::string clauseText = stringify(toString(*cl));
668  const std::string logTimerStatement =
669  LogStatement::tRecursiveRule(relationName, version, srcLocation, clauseText);
670  const std::string logSizeStatement =
671  LogStatement::nRecursiveRule(relationName, version, srcLocation, clauseText);
672  rule = mk<ram::LogRelationTimer>(
673  std::move(rule), logTimerStatement, translateNewRelation(rel));
674  }
675 
676  // add debug info
677  std::ostringstream ds;
678  ds << toString(*cl) << "\nin file ";
679  ds << cl->getSrcLoc();
680  rule = mk<ram::DebugInfo>(std::move(rule), ds.str());
681 
682  // add to loop body
683  appendStmt(loopRelSeq, std::move(rule));
684 
685  // increment version counter
686  version++;
687  }
688 
689  if (cl->getExecutionPlan() != nullptr) {
690  // ensure that all required versions have been created, as expected
691  int maxVersion = -1;
692  for (auto const& cur : cl->getExecutionPlan()->getOrders()) {
693  maxVersion = std::max(cur.first, maxVersion);
694  }
695  assert(version > maxVersion && "missing clause versions");
696  }
697  }
698 
699  // if there was no rule, continue
700  if (loopRelSeq.size() == 0) {
701  continue;
702  }
703 
704  // label all versions
705  if (Global::config().has("profile")) {
706  const std::string& relationName = toString(rel->getQualifiedName());
707  const SrcLocation& srcLocation = rel->getSrcLoc();
708  const std::string logTimerStatement = LogStatement::tRecursiveRelation(relationName, srcLocation);
709  const std::string logSizeStatement = LogStatement::nRecursiveRelation(relationName, srcLocation);
710  auto newStmt = mk<ram::LogRelationTimer>(
711  mk<ram::Sequence>(std::move(loopRelSeq)), logTimerStatement, translateNewRelation(rel));
712  loopRelSeq.clear();
713  appendStmt(loopRelSeq, std::move(newStmt));
714  }
715 
716  /* add rule computations of a relation to parallel statement */
717  appendStmt(loopSeq, mk<ram::Sequence>(std::move(loopRelSeq)));
718  }
719  auto loop = mk<ram::Parallel>(std::move(loopSeq));
720 
721  /* construct exit conditions for odd and even iteration */
722  auto addCondition = [](Own<ram::Condition>& cond, Own<ram::Condition> clause) {
723  cond = ((cond) ? mk<ram::Conjunction>(std::move(cond), std::move(clause)) : std::move(clause));
724  };
725 
726  Own<ram::Condition> exitCond;
727  VecOwn<ram::Statement> exitStmts;
728  for (const ast::Relation* rel : scc) {
729  addCondition(exitCond, mk<ram::EmptinessCheck>(translateNewRelation(rel)));
730  if (ioType->isLimitSize(rel)) {
731  Own<ram::Condition> limit =
732  mk<ram::Constraint>(BinaryConstraintOp::GE, mk<ram::RelationSize>(translateRelation(rel)),
733  mk<ram::SignedConstant>(ioType->getLimitSize(rel)));
734  appendStmt(exitStmts, mk<ram::Exit>(std::move(limit)));
735  }
736  }
737 
738  /* construct fixpoint loop */
739  VecOwn<ram::Statement> res;
740  if (preamble.size() > 0) {
741  appendStmt(res, mk<ram::Sequence>(std::move(preamble)));
742  }
743  if (!loop->getStatements().empty() && exitCond && updateTable.size() > 0) {
744  appendStmt(res,
745  mk<ram::Loop>(mk<ram::Sequence>(std::move(loop), mk<ram::Exit>(std::move(exitCond)),
746  mk<ram::Sequence>(std::move(exitStmts)), mk<ram::Sequence>(std::move(updateTable)))));
747  }
748  if (postamble.size() > 0) {
749  appendStmt(res, mk<ram::Sequence>(std::move(postamble)));
750  }
751  if (res.size() > 0) {
752  return mk<ram::Sequence>(std::move(res));
753  }
754 
755  fatal("Not Implemented");
756 }
757 
758 /** make a subroutine to search for subproofs */
759 Own<ram::Statement> AstToRamTranslator::makeSubproofSubroutine(const ast::Clause& clause) {
760  auto intermediateClause = mk<ast::Clause>(souffle::clone(clause.getHead()));
761 
762  // create a clone where all the constraints are moved to the end
763  for (auto bodyLit : clause.getBodyLiterals()) {
764  // first add all the things that are not constraints
765  if (!isA<ast::Constraint>(bodyLit)) {
766  intermediateClause->addToBody(souffle::clone(bodyLit));
767  }
768  }
769 
770  // now add all constraints
771  for (auto bodyLit : ast::getBodyLiterals<ast::Constraint>(clause)) {
772  intermediateClause->addToBody(souffle::clone(bodyLit));
773  }
774 
775  // name unnamed variables
776  nameUnnamedVariables(intermediateClause.get());
777 
778  // add constraint for each argument in head of atom
779  ast::Atom* head = intermediateClause->getHead();
780  size_t auxiliaryArity = auxArityAnalysis->getArity(head);
781  auto args = head->getArguments();
782  for (size_t i = 0; i < head->getArity() - auxiliaryArity; i++) {
783  auto arg = args[i];
784 
785  if (auto var = dynamic_cast<ast::Variable*>(arg)) {
786  // FIXME: float equiv (`FEQ`)
787  auto constraint = mk<ast::BinaryConstraint>(
788  BinaryConstraintOp::EQ, souffle::clone(var), mk<ast::SubroutineArgument>(i));
789  constraint->setFinalType(BinaryConstraintOp::EQ);
790  intermediateClause->addToBody(std::move(constraint));
791  } else if (auto func = dynamic_cast<ast::Functor*>(arg)) {
792  TypeAttribute returnType;
793  if (auto* inf = dynamic_cast<ast::IntrinsicFunctor*>(func)) {
794  assert(inf->getFinalReturnType().has_value() && "functor has missing return type");
795  returnType = inf->getFinalReturnType().value();
796  } else if (auto* udf = dynamic_cast<ast::UserDefinedFunctor*>(func)) {
797  assert(udf->getFinalReturnType().has_value() && "functor has missing return type");
798  returnType = udf->getFinalReturnType().value();
799  } else {
800  assert(false && "unexpected functor type");
801  }
803  auto constraint =
804  mk<ast::BinaryConstraint>(opEq, souffle::clone(func), mk<ast::SubroutineArgument>(i));
805  constraint->setFinalType(opEq);
806  intermediateClause->addToBody(std::move(constraint));
807  } else if (auto rec = dynamic_cast<ast::RecordInit*>(arg)) {
808  auto constraint = mk<ast::BinaryConstraint>(
809  BinaryConstraintOp::EQ, souffle::clone(rec), mk<ast::SubroutineArgument>(i));
810  constraint->setFinalType(BinaryConstraintOp::EQ);
811  intermediateClause->addToBody(std::move(constraint));
812  }
813  }
814 
815  // index of level argument in argument list
816  size_t levelIndex = head->getArguments().size() - auxiliaryArity;
817 
818  // add level constraints, i.e., that each body literal has height less than that of the head atom
819  const auto& bodyLiterals = intermediateClause->getBodyLiterals();
820  for (auto lit : bodyLiterals) {
821  if (auto atom = dynamic_cast<ast::Atom*>(lit)) {
822  auto arity = atom->getArity();
823  auto atomArgs = atom->getArguments();
824  // arity - 1 is the level number in body atoms
825  auto constraint = mk<ast::BinaryConstraint>(BinaryConstraintOp::LT,
826  souffle::clone(atomArgs[arity - 1]), mk<ast::SubroutineArgument>(levelIndex));
827  constraint->setFinalType(BinaryConstraintOp::LT);
828  intermediateClause->addToBody(std::move(constraint));
829  }
830  }
831  return ProvenanceClauseTranslator(*this).translateClause(*intermediateClause, clause);
832 }
833 
834 /** make a subroutine to search for subproofs for the non-existence of a tuple */
835 Own<ram::Statement> AstToRamTranslator::makeNegationSubproofSubroutine(const ast::Clause& clause) {
836  // TODO (taipan-snake): Currently we only deal with atoms (no constraints or negations or aggregates
837  // or anything else...)
838  //
839  // The resulting subroutine looks something like this:
840  // IF (arg(0), arg(1), _, _) IN rel_1:
841  // return 1
842  // IF (arg(0), arg(1), _ ,_) NOT IN rel_1:
843  // return 0
844  // ...
845 
846  // clone clause for mutation, rearranging constraints to be at the end
847  auto clauseReplacedAggregates = mk<ast::Clause>(souffle::clone(clause.getHead()));
848 
849  // create a clone where all the constraints are moved to the end
850  for (auto bodyLit : clause.getBodyLiterals()) {
851  // first add all the things that are not constraints
852  if (!isA<ast::Constraint>(bodyLit)) {
853  clauseReplacedAggregates->addToBody(souffle::clone(bodyLit));
854  }
855  }
856 
857  // now add all constraints
858  for (auto bodyLit : ast::getBodyLiterals<ast::Constraint>(clause)) {
859  clauseReplacedAggregates->addToBody(souffle::clone(bodyLit));
860  }
861 
862  int aggNumber = 0;
863  struct AggregatesToVariables : public ast::NodeMapper {
864  int& aggNumber;
865 
866  AggregatesToVariables(int& aggNumber) : aggNumber(aggNumber) {}
867 
868  Own<ast::Node> operator()(Own<ast::Node> node) const override {
869  if (dynamic_cast<ast::Aggregator*>(node.get()) != nullptr) {
870  return mk<ast::Variable>("agg_" + std::to_string(aggNumber++));
871  }
872 
873  node->apply(*this);
874  return node;
875  }
876  };
877 
878  AggregatesToVariables aggToVar(aggNumber);
879  clauseReplacedAggregates->apply(aggToVar);
880 
881  // build a vector of unique variables
882  std::vector<const ast::Variable*> uniqueVariables;
883 
884  visitDepthFirst(*clauseReplacedAggregates, [&](const ast::Variable& var) {
885  if (var.getName().find("@level_num") == std::string::npos) {
886  // use find_if since uniqueVariables stores pointers, and we need to dereference the pointer to
887  // check equality
888  if (std::find_if(uniqueVariables.begin(), uniqueVariables.end(),
889  [&](const ast::Variable* v) { return *v == var; }) == uniqueVariables.end()) {
890  uniqueVariables.push_back(&var);
891  }
892  }
893  });
894 
895  // a mapper to replace variables with subroutine arguments
896  struct VariablesToArguments : public ast::NodeMapper {
897  const std::vector<const ast::Variable*>& uniqueVariables;
898 
899  VariablesToArguments(const std::vector<const ast::Variable*>& uniqueVariables)
900  : uniqueVariables(uniqueVariables) {}
901 
902  Own<ast::Node> operator()(Own<ast::Node> node) const override {
903  // replace unknown variables
904  if (auto varPtr = dynamic_cast<const ast::Variable*>(node.get())) {
905  if (varPtr->getName().find("@level_num") == std::string::npos) {
906  size_t argNum = std::find_if(uniqueVariables.begin(), uniqueVariables.end(),
907  [&](const ast::Variable* v) { return *v == *varPtr; }) -
908  uniqueVariables.begin();
909 
910  return mk<ast::SubroutineArgument>(argNum);
911  } else {
912  return mk<ast::UnnamedVariable>();
913  }
914  }
915 
916  // apply recursive
917  node->apply(*this);
918 
919  // otherwise nothing
920  return node;
921  }
922  };
923 
924  // the structure of this subroutine is a sequence where each nested statement is a search in each
925  // relation
926  VecOwn<ram::Statement> searchSequence;
927 
928  // make a copy so that when we mutate clause, pointers to objects in newClause are not affected
929  auto newClause = souffle::clone(clauseReplacedAggregates);
930 
931  // go through each body atom and create a return
932  size_t litNumber = 0;
933  for (const auto& lit : newClause->getBodyLiterals()) {
934  if (auto atom = dynamic_cast<ast::Atom*>(lit)) {
935  size_t auxiliaryArity = auxArityAnalysis->getArity(atom);
936 
937  auto relName = translateRelation(atom);
938  // construct a query
939  VecOwn<ram::Expression> query;
940 
941  // translate variables to subroutine arguments
942  VariablesToArguments varsToArgs(uniqueVariables);
943  atom->apply(varsToArgs);
944 
945  auto atomArgs = atom->getArguments();
946  // add each value (subroutine argument) to the search query
947  for (size_t i = 0; i < atom->getArity() - auxiliaryArity; i++) {
948  auto arg = atomArgs[i];
949  query.push_back(translateValue(arg, ValueIndex()));
950  }
951 
952  // fill up query with nullptrs for the provenance columns
953  for (size_t i = 0; i < auxiliaryArity; i++) {
954  query.push_back(mk<ram::UndefValue>());
955  }
956 
957  // ensure the length of query tuple is correct
958  assert(query.size() == atom->getArity() && "wrong query tuple size");
959 
960  // create existence checks to check if the tuple exists or not
961  auto existenceCheck = mk<ram::ExistenceCheck>(relName, std::move(query));
962  auto negativeExistenceCheck = mk<ram::Negation>(souffle::clone(existenceCheck));
963 
964  // return true if the tuple exists
965  VecOwn<ram::Expression> returnTrue;
966  returnTrue.push_back(mk<ram::SignedConstant>(1));
967 
968  // return false if the tuple exists
969  VecOwn<ram::Expression> returnFalse;
970  returnFalse.push_back(mk<ram::SignedConstant>(0));
971 
972  // create a ram::Query to return true/false
973  appendStmt(searchSequence, mk<ram::Query>(mk<ram::Filter>(std::move(existenceCheck),
974  mk<ram::SubroutineReturn>(std::move(returnTrue)))));
975  appendStmt(searchSequence, mk<ram::Query>(mk<ram::Filter>(std::move(negativeExistenceCheck),
976  mk<ram::SubroutineReturn>(std::move(returnFalse)))));
977  } else if (auto neg = dynamic_cast<ast::Negation*>(lit)) {
978  auto atom = neg->getAtom();
979 
980  size_t auxiliaryArity = auxArityAnalysis->getArity(atom);
981  auto relName = translateRelation(atom);
982  // construct a query
983  VecOwn<ram::Expression> query;
984 
985  // translate variables to subroutine arguments
986  VariablesToArguments varsToArgs(uniqueVariables);
987  atom->apply(varsToArgs);
988 
989  auto atomArgs = atom->getArguments();
990  // add each value (subroutine argument) to the search query
991  for (size_t i = 0; i < atom->getArity() - auxiliaryArity; i++) {
992  auto arg = atomArgs[i];
993  query.push_back(translateValue(arg, ValueIndex()));
994  }
995 
996  // fill up query with nullptrs for the provenance columns
997  for (size_t i = 0; i < auxiliaryArity; i++) {
998  query.push_back(mk<ram::UndefValue>());
999  }
1000 
1001  // ensure the length of query tuple is correct
1002  assert(query.size() == atom->getArity() && "wrong query tuple size");
1003 
1004  // create existence checks to check if the tuple exists or not
1005  auto existenceCheck = mk<ram::ExistenceCheck>(relName, std::move(query));
1006  auto negativeExistenceCheck = mk<ram::Negation>(souffle::clone(existenceCheck));
1007 
1008  // return true if the tuple exists
1009  VecOwn<ram::Expression> returnTrue;
1010  returnTrue.push_back(mk<ram::SignedConstant>(1));
1011 
1012  // return false if the tuple exists
1013  VecOwn<ram::Expression> returnFalse;
1014  returnFalse.push_back(mk<ram::SignedConstant>(0));
1015 
1016  // create a ram::Query to return true/false
1017  appendStmt(searchSequence, mk<ram::Query>(mk<ram::Filter>(std::move(existenceCheck),
1018  mk<ram::SubroutineReturn>(std::move(returnFalse)))));
1019  appendStmt(searchSequence, mk<ram::Query>(mk<ram::Filter>(std::move(negativeExistenceCheck),
1020  mk<ram::SubroutineReturn>(std::move(returnTrue)))));
1021 
1022  } else if (auto con = dynamic_cast<ast::Constraint*>(lit)) {
1023  VariablesToArguments varsToArgs(uniqueVariables);
1024  con->apply(varsToArgs);
1025 
1026  // translate to a ram::Condition
1027  auto condition = translateConstraint(con, ValueIndex());
1028  auto negativeCondition = mk<ram::Negation>(souffle::clone(condition));
1029 
1030  // create a return true value
1031  VecOwn<ram::Expression> returnTrue;
1032  returnTrue.push_back(mk<ram::SignedConstant>(1));
1033 
1034  // create a return false value
1035  VecOwn<ram::Expression> returnFalse;
1036  returnFalse.push_back(mk<ram::SignedConstant>(0));
1037 
1038  appendStmt(searchSequence, mk<ram::Query>(mk<ram::Filter>(std::move(condition),
1039  mk<ram::SubroutineReturn>(std::move(returnTrue)))));
1040  appendStmt(searchSequence, mk<ram::Query>(mk<ram::Filter>(std::move(negativeCondition),
1041  mk<ram::SubroutineReturn>(std::move(returnFalse)))));
1042  }
1043 
1044  litNumber++;
1045  }
1046 
1047  return mk<ram::Sequence>(std::move(searchSequence));
1048 }
1049 
1050 bool AstToRamTranslator::removeADTs(const ast::TranslationUnit& translationUnit) {
1051  struct ADTsFuneral : public ast::NodeMapper {
1052  mutable bool changed{false};
1053  const ast::analysis::SumTypeBranchesAnalysis& sumTypesBranches;
1054 
1055  ADTsFuneral(const ast::TranslationUnit& tu)
1056  : sumTypesBranches(*tu.getAnalysis<ast::analysis::SumTypeBranchesAnalysis>()) {}
1057 
1058  Own<ast::Node> operator()(Own<ast::Node> node) const override {
1059  // Rewrite sub-expressions first
1060  node->apply(*this);
1061 
1062  if (!isA<ast::BranchInit>(node)) {
1063  return node;
1064  }
1065 
1066  changed = true;
1067  auto& adt = *as<ast::BranchInit>(node);
1068  auto& type = sumTypesBranches.unsafeGetType(adt.getConstructor());
1069  auto& branches = type.getBranches();
1070 
1071  // Find branch ID.
1072  ast::analysis::AlgebraicDataType::Branch searchDummy{adt.getConstructor(), {}};
1073  auto iterToBranch = std::lower_bound(branches.begin(), branches.end(), searchDummy,
1074  [](const ast::analysis::AlgebraicDataType::Branch& left,
1075  const ast::analysis::AlgebraicDataType::Branch& right) {
1076  return left.name < right.name;
1077  });
1078 
1079  // Branch id corresponds to the position in lexicographical ordering.
1080  auto branchID = std::distance(std::begin(branches), iterToBranch);
1081 
1082  if (isADTEnum(type)) {
1083  auto branchTag = mk<ast::NumericConstant>(branchID);
1084  branchTag->setFinalType(ast::NumericConstant::Type::Int);
1085  return branchTag;
1086  } else {
1087  // Collect branch arguments
1088  VecOwn<ast::Argument> branchArguments;
1089  for (auto* arg : adt.getArguments()) {
1090  branchArguments.emplace_back(arg->clone());
1091  }
1092 
1093  // Branch is stored either as [branch_id, [arguments]]
1094  // or [branch_id, argument] in case of a single argument.
1095  auto branchArgs = [&]() -> Own<ast::Argument> {
1096  if (branchArguments.size() != 1) {
1097  return mk<ast::Argument, ast::RecordInit>(std::move(branchArguments));
1098  } else {
1099  return std::move(branchArguments.at(0));
1100  }
1101  }();
1102 
1103  // Arguments for the resulting record [branch_id, branch_args].
1104  VecOwn<ast::Argument> finalRecordArgs;
1105 
1106  auto branchTag = mk<ast::NumericConstant>(branchID);
1107  branchTag->setFinalType(ast::NumericConstant::Type::Int);
1108  finalRecordArgs.push_back(std::move(branchTag));
1109  finalRecordArgs.push_back(std::move(branchArgs));
1110 
1111  return mk<ast::RecordInit>(std::move(finalRecordArgs), adt.getSrcLoc());
1112  }
1113  }
1114  };
1115 
1116  ADTsFuneral mapper(translationUnit);
1117  translationUnit.getProgram().apply(mapper);
1118  return mapper.changed;
1119 }
1120 
1121 /** translates the given datalog program into an equivalent RAM program */
1122 void AstToRamTranslator::translateProgram(const ast::TranslationUnit& translationUnit) {
1123  // keep track of relevant analyses
1124  ioType = translationUnit.getAnalysis<ast::analysis::IOTypeAnalysis>();
1125  typeEnv = &translationUnit.getAnalysis<ast::analysis::TypeEnvironmentAnalysis>()->getTypeEnvironment();
1126  const auto* recursiveClauses = translationUnit.getAnalysis<ast::analysis::RecursiveClausesAnalysis>();
1127  const auto& sccGraph = *translationUnit.getAnalysis<ast::analysis::SCCGraphAnalysis>();
1128  const auto& sccOrder = *translationUnit.getAnalysis<ast::analysis::TopologicallySortedSCCGraphAnalysis>();
1129  const auto& expirySchedule =
1130  translationUnit.getAnalysis<ast::analysis::RelationScheduleAnalysis>()->schedule();
1131  auxArityAnalysis = translationUnit.getAnalysis<ast::analysis::AuxiliaryArityAnalysis>();
1132  functorAnalysis = translationUnit.getAnalysis<ast::analysis::FunctorAnalysis>();
1133  polyAnalysis = translationUnit.getAnalysis<ast::analysis::PolymorphicObjectsAnalysis>();
1134 
1135  // set up the final fixed types
1136  // TODO (azreika): should be removed once the translator is refactored to avoid cloning
1137  visitDepthFirst(*program, [&](const ast::NumericConstant& nc) {
1138  const_cast<ast::NumericConstant&>(nc).setFinalType(polyAnalysis->getInferredType(&nc));
1139  });
1140  visitDepthFirst(*program, [&](const ast::Aggregator& aggr) {
1141  const_cast<ast::Aggregator&>(aggr).setFinalType(polyAnalysis->getOverloadedOperator(&aggr));
1142  });
1143  visitDepthFirst(*program, [&](const ast::BinaryConstraint& bc) {
1144  const_cast<ast::BinaryConstraint&>(bc).setFinalType(polyAnalysis->getOverloadedOperator(&bc));
1145  });
1146  visitDepthFirst(*program, [&](const ast::IntrinsicFunctor& inf) {
1147  const_cast<ast::IntrinsicFunctor&>(inf).setFinalOpType(polyAnalysis->getOverloadedFunctionOp(&inf));
1148  const_cast<ast::IntrinsicFunctor&>(inf).setFinalReturnType(functorAnalysis->getReturnType(&inf));
1149  });
1150  visitDepthFirst(*program, [&](const ast::UserDefinedFunctor& udf) {
1151  const_cast<ast::UserDefinedFunctor&>(udf).setFinalReturnType(functorAnalysis->getReturnType(&udf));
1152  });
1153 
1154  // determine the sips to use
1155  std::string sipsChosen = "all-bound";
1156  if (Global::config().has("RamSIPS")) {
1157  sipsChosen = Global::config().get("RamSIPS");
1158  }
1159  sips = ast::SipsMetric::create(sipsChosen, translationUnit);
1160 
1161  // replace ADTs with record representatives
1162  removeADTs(translationUnit);
1163 
1164  // handle the case of an empty SCC graph
1165  if (sccGraph.getNumberOfSCCs() == 0) return;
1166 
1167  // a function to load relations
1168  const auto& makeRamLoad = [&](VecOwn<ram::Statement>& current, const ast::Relation* relation) {
1169  for (auto directives : getInputDirectives(relation)) {
1170  Own<ram::Statement> statement = mk<ram::IO>(translateRelation(relation), directives);
1171  if (Global::config().has("profile")) {
1172  const std::string logTimerStatement = LogStatement::tRelationLoadTime(
1173  toString(relation->getQualifiedName()), relation->getSrcLoc());
1174  statement = mk<ram::LogRelationTimer>(
1175  std::move(statement), logTimerStatement, translateRelation(relation));
1176  }
1177  appendStmt(current, std::move(statement));
1178  }
1179  };
1180 
1181  // a function to store relations
1182  const auto& makeRamStore = [&](VecOwn<ram::Statement>& current, const ast::Relation* relation) {
1183  for (auto directives : getOutputDirectives(relation)) {
1184  Own<ram::Statement> statement = mk<ram::IO>(translateRelation(relation), directives);
1185  if (Global::config().has("profile")) {
1186  const std::string logTimerStatement = LogStatement::tRelationSaveTime(
1187  toString(relation->getQualifiedName()), relation->getSrcLoc());
1188  statement = mk<ram::LogRelationTimer>(
1189  std::move(statement), logTimerStatement, translateRelation(relation));
1190  }
1191  appendStmt(current, std::move(statement));
1192  }
1193  };
1194 
1195  // a function to drop relations
1196  const auto& makeRamClear = [&](VecOwn<ram::Statement>& current, const ast::Relation* relation) {
1197  appendStmt(current, mk<ram::Clear>(translateRelation(relation)));
1198  };
1199 
1200  // create all Ram relations in ramRels
1201  for (const auto& scc : sccOrder.order()) {
1202  const auto& isRecursive = sccGraph.isRecursive(scc);
1203  const auto& allInterns = sccGraph.getInternalRelations(scc);
1204  for (const auto& rel : allInterns) {
1205  std::string name = rel->getQualifiedName().toString();
1206  auto arity = rel->getArity();
1207  auto auxiliaryArity = auxArityAnalysis->getArity(rel);
1208  auto representation = rel->getRepresentation();
1209  const auto& attributes = rel->getAttributes();
1210 
1211  std::vector<std::string> attributeNames;
1212  std::vector<std::string> attributeTypeQualifiers;
1213  for (size_t i = 0; i < rel->getArity(); ++i) {
1214  attributeNames.push_back(attributes[i]->getName());
1215  if (typeEnv != nullptr) {
1216  attributeTypeQualifiers.push_back(
1217  getTypeQualifier(typeEnv->getType(attributes[i]->getTypeName())));
1218  }
1219  }
1220  ramRels[name] = mk<ram::Relation>(
1221  name, arity, auxiliaryArity, attributeNames, attributeTypeQualifiers, representation);
1222 
1223  // recursive relations also require @delta and @new variants, with the same signature
1224  if (isRecursive) {
1225  std::string deltaName = "@delta_" + name;
1226  std::string newName = "@new_" + name;
1227  ramRels[deltaName] = mk<ram::Relation>(deltaName, arity, auxiliaryArity, attributeNames,
1228  attributeTypeQualifiers, representation);
1229  ramRels[newName] = mk<ram::Relation>(newName, arity, auxiliaryArity, attributeNames,
1230  attributeTypeQualifiers, representation);
1231  }
1232  }
1233  }
1234 
1235  // maintain the index of the SCC within the topological order
1236  size_t indexOfScc = 0;
1237 
1238  // iterate over each SCC according to the topological order
1239  for (const auto& scc : sccOrder.order()) {
1240  // make a new ram statement for the current SCC
1241  VecOwn<ram::Statement> current;
1242 
1243  // find out if the current SCC is recursive
1244  const auto& isRecursive = sccGraph.isRecursive(scc);
1245 
1246  // make variables for particular sets of relations contained within the current SCC, and,
1247  // predecessors and successor SCCs thereof
1248  const auto& allInterns = sccGraph.getInternalRelations(scc);
1249  const auto& internIns = sccGraph.getInternalInputRelations(scc);
1250  const auto& internOuts = sccGraph.getInternalOutputRelations(scc);
1251 
1252  // make a variable for all relations that are expired at the current SCC
1253  const auto& internExps = expirySchedule.at(indexOfScc).expired();
1254 
1255  // load all internal input relations from the facts dir with a .facts extension
1256  for (const auto& relation : internIns) {
1257  makeRamLoad(current, relation);
1258  }
1259 
1260  // compute the relations themselves
1261  Own<ram::Statement> bodyStatement =
1262  (!isRecursive) ? translateNonRecursiveRelation(
1263  *((const ast::Relation*)*allInterns.begin()), recursiveClauses)
1264  : translateRecursiveRelation(allInterns, recursiveClauses);
1265  appendStmt(current, std::move(bodyStatement));
1266 
1267  // store all internal output relations to the output dir with a .csv extension
1268  for (const auto& relation : internOuts) {
1269  makeRamStore(current, relation);
1270  }
1271 
1272  // if provenance is disabled, drop all relations expired as per the topological order
1273  if (!Global::config().has("provenance")) {
1274  for (const auto& relation : internExps) {
1275  makeRamClear(current, relation);
1276  }
1277  }
1278 
1279  // create subroutine for this stratum
1280  ramSubs["stratum_" + std::to_string(indexOfScc)] = mk<ram::Sequence>(std::move(current));
1281  indexOfScc++;
1282  }
1283 
1284  // invoke all strata
1285  VecOwn<ram::Statement> res;
1286  for (size_t i = 0; i < indexOfScc; i++) {
1287  appendStmt(res, mk<ram::Call>("stratum_" + std::to_string(i)));
1288  }
1289 
1290  // add main timer if profiling
1291  if (res.size() > 0 && Global::config().has("profile")) {
1292  auto newStmt = mk<ram::LogTimer>(mk<ram::Sequence>(std::move(res)), LogStatement::runtime());
1293  res.clear();
1294  appendStmt(res, std::move(newStmt));
1295  }
1296 
1297  // done for main prog
1298  ramMain = mk<ram::Sequence>(std::move(res));
1299 
1300  // add subroutines for each clause
1301  if (Global::config().has("provenance")) {
1302  visitDepthFirst(*program, [&](const ast::Clause& clause) {
1303  std::stringstream relName;
1304  relName << clause.getHead()->getQualifiedName();
1305 
1306  // do not add subroutines for info relations or facts
1307  if (relName.str().find("@info") != std::string::npos || clause.getBodyLiterals().empty()) {
1308  return;
1309  }
1310 
1311  std::string subroutineLabel =
1312  relName.str() + "_" + std::to_string(getClauseNum(program, &clause)) + "_subproof";
1313  ramSubs[subroutineLabel] = makeSubproofSubroutine(clause);
1314 
1315  std::string negationSubroutineLabel = relName.str() + "_" +
1316  std::to_string(getClauseNum(program, &clause)) +
1317  "_negation_subproof";
1318  ramSubs[negationSubroutineLabel] = makeNegationSubproofSubroutine(clause);
1319  });
1320  }
1321 }
1322 
1323 Own<ram::TranslationUnit> AstToRamTranslator::translateUnit(ast::TranslationUnit& tu) {
1324  auto ram_start = std::chrono::high_resolution_clock::now();
1325  program = &tu.getProgram();
1326 
1327  translateProgram(tu);
1328  SymbolTable& symTab = getSymbolTable();
1329  ErrorReport& errReport = tu.getErrorReport();
1330  DebugReport& debugReport = tu.getDebugReport();
1331  VecOwn<ram::Relation> rels;
1332  for (auto& cur : ramRels) {
1333  rels.push_back(std::move(cur.second));
1334  }
1335  if (ramMain == nullptr) {
1336  ramMain = mk<ram::Sequence>();
1337  }
1338  auto ramProg = mk<ram::Program>(std::move(rels), std::move(ramMain), std::move(ramSubs));
1339  if (!Global::config().get("debug-report").empty()) {
1340  if (ramProg) {
1341  auto ram_end = std::chrono::high_resolution_clock::now();
1342  std::string runtimeStr =
1343  "(" + std::to_string(std::chrono::duration<double>(ram_end - ram_start).count()) + "s)";
1344  std::stringstream ramProgStr;
1345  ramProgStr << *ramProg;
1346  debugReport.addSection("ram-program", "RAM Program " + runtimeStr, ramProgStr.str());
1347  }
1348  }
1349  return mk<ram::TranslationUnit>(std::move(ramProg), std::move(symTab), errReport, debugReport);
1350 }
1351 
1352 } // namespace souffle::ast2ram
souffle::LogStatement::nNonrecursiveRule
static const std::string nNonrecursiveRule(const std::string &relationName, const SrcLocation &srcLocation, const std::string &datalogText)
Definition: LogStatement.h:76
souffle::ast2ram::ValueIndex::getDefinitionPoint
const Location & getDefinitionPoint(const ast::Variable &var) const
Definition: ValueIndex.cpp:53
souffle::RamSignedFromString
RamSigned RamSignedFromString(const std::string &str, std::size_t *position=nullptr, const int base=10)
Converts a string to a RamSigned.
Definition: StringUtil.h:51
BinaryConstraintOps.h
UserDefinedOperator.h
souffle::ast::analysis::FunctorAnalysis::isMultiResult
static bool isMultiResult(const Functor &functor)
Definition: Functor.cpp:53
RelationSchedule.h
souffle::ast::BinaryConstraint::getFinalType
std::optional< BinaryConstraintOp > getFinalType() const
Definition: BinaryConstraint.h:99
souffle::ast2ram::AstToRamTranslator::getConstantRamRepresentation
RamDomain getConstantRamRepresentation(const ast::Constant &constant)
Get ram representation of constant.
Definition: AstToRamTranslator.cpp:418
PackRecord.h
TranslationUnit.h
souffle::ast2ram::AstToRamTranslator::translateNonRecursiveRelation
Own< ram::Statement > translateNonRecursiveRelation(const ast::Relation &rel, const ast::analysis::RecursiveClausesAnalysis *recursiveClauses)
translate RAM code for the non-recursive clauses of the given relation.
Definition: AstToRamTranslator.cpp:452
Functor.h
NilConstant.h
souffle::ast::Visitor
The generic base type of all AstVisitors realizing the dispatching of visitor calls.
Definition: Visitor.h:87
UnsignedConstant.h
souffle::ast::Atom::getArguments
std::vector< Argument * > getArguments() const
Return arguments.
Definition: Atom.h:77
Constraint.h
Call.h
UnnamedVariable.h
RecursiveClauses.h
souffle::LogStatement::cRecursiveRelation
static const std::string cRecursiveRelation(const std::string &relationName, const SrcLocation &srcLocation)
Definition: LogStatement.h:118
Scan.h
souffle::ast2ram::AstToRamTranslator::auxArityAnalysis
const ast::analysis::AuxiliaryArityAnalysis * auxArityAnalysis
Auxiliary Arity Analysis.
Definition: AstToRamTranslator.h:136
TypeAttribute
Type attribute class.
DebugReport.h
Exit.h
souffle::RamDomain
int32_t RamDomain
Definition: RamTypes.h:56
souffle::ast::BinaryConstraint::getLHS
Argument * getLHS() const
Return left-hand side argument.
Definition: BinaryConstraint.h:59
Negation.h
IOType.h
souffle::ast::analysis::FunctorAnalysis
Definition: Functor.h:39
Project.h
souffle::ast::analysis::isADTEnum
bool isADTEnum(const AlgebraicDataType &type)
Determine if ADT is enumerations (are all constructors empty)
Definition: TypeSystem.cpp:377
AstToRamTranslator.h
Clear.h
souffle::RelationRepresentation::EQREL
@ EQREL
Directive.h
LogTimer.h
SymbolTable.h
SrcLocation.h
souffle::ast::analysis::PolymorphicObjectsAnalysis
Definition: PolymorphicObjects.h:39
souffle::ast::analysis::FunctorAnalysis::getArgTypes
const std::vector< TypeAttribute > & getArgTypes(const UserDefinedFunctor &udf) const
Definition: Functor.cpp:44
souffle::LogStatement::tRecursiveRelation
static const std::string tRecursiveRelation(const std::string &relationName, const SrcLocation &srcLocation)
Definition: LogStatement.h:102
souffle::ast::analysis::RelationScheduleAnalysis
Analysis pass computing a schedule for computing relations.
Definition: RelationSchedule.h:82
souffle::ast::BinaryConstraint::getRHS
Argument * getRHS() const
Return right-hand side argument.
Definition: BinaryConstraint.h:64
souffle::ast2ram::AstToRamTranslator::nameUnnamedVariables
void nameUnnamedVariables(ast::Clause *clause)
assigns names to unnamed variables such that enclosing constructs may be cloned without losing the va...
Definition: AstToRamTranslator.cpp:519
souffle::ast::getClauseNum
size_t getClauseNum(const Program *program, const Clause *clause)
Returns the index of a clause within its relation, ignoring facts.
Definition: Utils.cpp:150
souffle::LogStatement::runtime
static const std::string runtime()
Definition: LogStatement.h:139
souffle::Own
std::unique_ptr< A > Own
Definition: ContainerUtil.h:42
souffle::ast2ram::AstToRamTranslator::functorAnalysis
const ast::analysis::FunctorAnalysis * functorAnalysis
Functors' analysis.
Definition: AstToRamTranslator.h:133
souffle::ast2ram::AstToRamTranslator::translateDeltaRelation
std::string translateDeltaRelation(const ast::Relation *rel)
translate a temporary delta relation to a RAM relation for semi-naive evaluation
Definition: AstToRamTranslator.cpp:228
relation
Relation & relation
Definition: Reader.h:130
souffle::BinaryConstraintOp::EQ
@ EQ
LogRelationTimer.h
souffle::ast2ram::AstToRamTranslator::getInputDirectives
std::vector< std::map< std::string, std::string > > getInputDirectives(const ast::Relation *rel)
Definition: AstToRamTranslator.cpp:170
souffle::ast::analysis::AlgebraicDataType::Branch
Definition: TypeSystem.h:201
MiscUtil.h
Transformer.h
souffle::ast::Relation
Defines a relation with a name, attributes, qualifiers, and internal representation.
Definition: Relation.h:49
souffle::ast::Clause
Intermediate representation of a horn clause.
Definition: Clause.h:51
souffle::ast2ram::Location
Definition: Location.h:29
Constraint.h
souffle::ast2ram::AstToRamTranslator::program
const ast::Program * program
AST program.
Definition: AstToRamTranslator.h:124
Filter.h
souffle::DebugReport::addSection
void addSection(DebugReportSection section)
Definition: DebugReport.h:93
SubroutineArgument.h
souffle::ast2ram::AstToRamTranslator::translateRelation
std::string translateRelation(const ast::Atom *atom)
a utility to translate atoms to relations
Definition: AstToRamTranslator.cpp:219
DebugInfo.h
EmptinessCheck.h
Swap.h
souffle::ast::analysis::Variable
A variable to be utilized within constraints to be handled by the constraint solver.
Definition: ConstraintSystem.h:41
Relation.h
IntrinsicFunctor.h
souffle::ast2ram::ClauseTranslator::translateClause
Own< ram::Statement > translateClause(const ast::Clause &clause, const ast::Clause &originalClause, const int version=0)
generate RAM code for a clause
Definition: ClauseTranslator.cpp:61
souffle::unescape
std::string unescape(const std::string &inputString, const std::string &needle, const std::string &replacement)
Definition: StringUtil.h:398
souffle::ast::analysis::IOTypeAnalysis::isLimitSize
bool isLimitSize(const Relation *relation) const
Definition: IOType.h:61
souffle::BinaryConstraintOp::FEQ
@ FEQ
souffle::ast::Atom
An atom class.
Definition: Atom.h:51
souffle::ast::SipsMetric::create
static std::unique_ptr< SipsMetric > create(const std::string &heuristic, const TranslationUnit &tu)
Create a SIPS metric based on a given heuristic.
Definition: SipsMetric.cpp:68
souffle::LogStatement::nRecursiveRule
static const std::string nRecursiveRule(const std::string &relationName, const int version, const SrcLocation &srcLocation, const std::string &datalogText)
Definition: LogStatement.h:93
j
var j
Definition: htmlJsChartistMin.h:15
Utils.h
Program.h
SCCGraph.h
NodeMapper.h
souffle::ast::NumericConstant::Type::Int
@ Int
Constant.h
souffle::ast2ram::AstToRamTranslator::AstToRamTranslator
AstToRamTranslator()
ProvenanceClauseTranslator.h
souffle::ast::Argument
An abstract class for arguments.
Definition: Argument.h:33
Global.h
souffle::ast2ram::AstToRamTranslator::getEvaluationArity
size_t getEvaluationArity(const ast::Atom *atom) const
determine the auxiliary for relations
Definition: AstToRamTranslator.cpp:154
UserDefinedFunctor.h
souffle::toString
const std::string & toString(const std::string &str)
A generic function converting strings into strings (trivial case).
Definition: StringUtil.h:234
StringConstant.h
Argument.h
AuxArity.h
souffle::SymbolTable::lookup
RamDomain lookup(const std::string &symbol)
Find the index of a symbol in the table, inserting a new symbol if it does not exist there already.
Definition: SymbolTable.h:124
souffle::LogStatement::nRecursiveRelation
static const std::string nRecursiveRelation(const std::string &relationName, const SrcLocation &srcLocation)
Definition: LogStatement.h:110
souffle::now
time_point now()
Definition: MiscUtil.h:89
ProvenanceExistenceCheck.h
souffle::ast::Atom::getQualifiedName
const QualifiedName & getQualifiedName() const
Return qualified name.
Definition: Atom.h:57
souffle::stringify
std::string stringify(const std::string &input)
Stringify a string using escapes for escape, newline, tab, double-quotes and semicolons.
Definition: StringUtil.h:334
souffle::clone
auto clone(const std::vector< A * > &xs)
Definition: ContainerUtil.h:172
souffle::ast2ram::Location::element
const int element
Definition: Location.h:35
i
size_t i
Definition: json11.h:663
souffle::ast::analysis::TopologicallySortedSCCGraphAnalysis
Analysis pass computing a topologically sorted strongly connected component (SCC) graph.
Definition: TopologicallySortedSCCGraph.h:49
ContainerUtil.h
TopologicallySortedSCCGraph.h
souffle::ast::getRelation
Relation * getRelation(const Program &program, const QualifiedName &name)
Returns the relation with the given name in the program.
Definition: Utils.cpp:101
Relation.h
souffle::join
detail::joined_sequence< Iter, Printer > join(const Iter &a, const Iter &b, const std::string &sep, const Printer &p)
Creates an object to be forwarded to some output stream for printing sequences of elements interspers...
Definition: StreamUtil.h:175
souffle::DebugReport
Class representing a HTML report, consisting of a list of sections.
Definition: DebugReport.h:87
souffle::ast2ram::AstToRamTranslator::translateConstraint
Own< ram::Condition > translateConstraint(const ast::Literal *arg, const ValueIndex &index)
translate an AST constraint to a RAM condition
Definition: AstToRamTranslator.cpp:340
souffle::BinaryConstraintOp::GE
@ GE
souffle::ast2ram::ValueIndex
Definition: ValueIndex.h:36
souffle::LogStatement::tNonrecursiveRelation
static const std::string tNonrecursiveRelation(const std::string &relationName, const SrcLocation &srcLocation)
Definition: LogStatement.h:37
souffle::ast2ram::AstToRamTranslator::~AstToRamTranslator
~AstToRamTranslator()
souffle::LogStatement::tNonrecursiveRule
static const std::string tNonrecursiveRule(const std::string &relationName, const SrcLocation &srcLocation, const std::string &datalogText)
Definition: LogStatement.h:68
souffle::ast::Atom::apply
void apply(const NodeMapper &map) override
Apply the mapper to all child nodes.
Definition: Atom.h:85
Atom.h
LogStatement.h
Condition.h
souffle::ast2ram::ValueIndex::isDefined
bool isDefined(const ast::Variable &var) const
Definition: ValueIndex.cpp:49
souffle::ast2ram::AstToRamTranslator::polyAnalysis
const ast::analysis::PolymorphicObjectsAnalysis * polyAnalysis
Polymorphic Objects Analysis.
Definition: AstToRamTranslator.h:139
souffle::ast::analysis::FunctorAnalysis::getReturnType
TypeAttribute getReturnType(const Functor *functor) const
Return return type of functor.
Definition: Functor.cpp:40
Literal.h
souffle::ast2ram::AstToRamTranslator::makeNegationSubproofSubroutine
Own< ram::Statement > makeNegationSubproofSubroutine(const ast::Clause &clause)
translate RAM code for subroutine to get subproofs for non-existence of a tuple
Definition: AstToRamTranslator.cpp:841
PolymorphicObjects.h
ExistenceCheck.h
souffle::ast::DirectiveType::printsize
@ printsize
AutoIncrement.h
souffle::ast2ram::ValueIndex::getGeneratorLoc
const Location & getGeneratorLoc(const ast::Argument &arg) const
Definition: ValueIndex.cpp:63
Utils.h
souffle::ast::Literal
Defines an abstract class for literals in a horn clause.
Definition: Literal.h:36
souffle::test::count
int count(const C &c)
Definition: table_test.cpp:40
TCB_SPAN_NAMESPACE_NAME::get
constexpr auto get(span< E, S > s) -> decltype(s[N])
Definition: span.h:599
souffle::LogStatement::tRelationLoadTime
static const std::string tRelationLoadTime(const std::string &relationName, const SrcLocation &srcLocation)
Definition: LogStatement.h:44
IO.h
Negation.h
BranchInit.h
RelationSize.h
souffle::BinaryConstraintOp::LT
@ LT
souffle::ast::DirectiveType::input
@ input
souffle::ast::getClauses
std::vector< Clause * > getClauses(const Program &program, const QualifiedName &relationName)
Returns a vector of clauses in the program describing the relation with the given name.
Definition: Utils.cpp:77
souffle::ast::Program::getDirectives
std::vector< Directive * > getDirectives() const
Return relation directives.
Definition: Program.h:75
TranslationUnit.h
Node.h
k
var k
Definition: htmlJsChartistMin.h:15
souffle::ast2ram::ClauseTranslator
Definition: ClauseTranslator.h:41
souffle::ast::Atom::getArity
size_t getArity() const
Return arity of the atom.
Definition: Atom.h:62
Location.h
souffle::ast::BinaryConstraint
Binary constraint class.
Definition: BinaryConstraint.h:53
souffle::ast2ram::AstToRamTranslator::getRelationName
static std::string getRelationName(const ast::QualifiedName &id)
converts the given relation identifier into a relation name
Definition: AstToRamTranslator.cpp:549
souffle::ast2ram::AstToRamTranslator::translateNewRelation
std::string translateNewRelation(const ast::Relation *rel)
translate a temporary new relation to a RAM relation for semi-naive evaluation
Definition: AstToRamTranslator.cpp:232
SipsMetric.h
Aggregator.h
SubroutineArgument.h
directives
std::vector< Own< Directive > > directives
Definition: ComponentInstantiation.cpp:66
souffle::ast2ram::appendStmt
void appendStmt(VecOwn< ram::Statement > &stmtList, Own< ram::Statement > stmt)
append statement to a list of statements
Definition: AstToRamTranslator.cpp:144
souffle::ast::QualifiedName::toString
std::string toString() const
convert to a string separated by fullstop
Definition: QualifiedName.h:71
souffle::ast::analysis::IOTypeAnalysis::getLimitSize
std::size_t getLimitSize(const Relation *relation) const
Definition: IOType.h:65
souffle::Global::config
static MainConfig & config()
Definition: Global.h:141
souffle::ast2ram::AstToRamTranslator::makeRamTupleElement
static Own< ram::TupleElement > makeRamTupleElement(const Location &loc)
create a RAM element access node
Definition: AstToRamTranslator.cpp:150
souffle::ast2ram::AstToRamTranslator::makeSubproofSubroutine
Own< ram::Statement > makeSubproofSubroutine(const ast::Clause &clause)
translate RAM code for subroutine to get subproofs
Definition: AstToRamTranslator.cpp:765
TupleElement.h
souffle::ast2ram::AstToRamTranslator::getSymbolTable
SymbolTable & getSymbolTable()
Return a symbol table.
Definition: AstToRamTranslator.cpp:335
souffle::ast::Aggregator
Defines the aggregator class.
Definition: Aggregator.h:53
Functor.h
QualifiedName.h
ValueIndex.h
Query.h
souffle::ast2ram::AstToRamTranslator
Main class for the AST->RAM translator.
Definition: AstToRamTranslator.h:71
Program.h
souffle::LogStatement::nNonrecursiveRelation
static const std::string nNonrecursiveRelation(const std::string &relationName, const SrcLocation &srcLocation)
Definition: LogStatement.h:60
souffle::LogStatement::tRecursiveRule
static const std::string tRecursiveRule(const std::string &relationName, const int version, const SrcLocation &srcLocation, const std::string &datalogText)
Definition: LogStatement.h:84
souffle::ast::DirectiveType::output
@ output
rule
Rule & rule
Definition: Reader.h:85
souffle::SrcLocation
A class describing a range in an input file.
Definition: SrcLocation.h:32
Sequence.h
SumTypeBranches.h
souffle::ast::NumericConstant::Type::Uint
@ Uint
Statement.h
souffle::fatal
void fatal(const char *format, const Args &... args)
Definition: MiscUtil.h:198
souffle::ast2ram::AstToRamTranslator::translateValue
Own< ram::Expression > translateValue(const ast::Argument *arg, const ValueIndex &index)
translate an AST argument to a RAM value
Definition: AstToRamTranslator.cpp:236
Visitor.h
souffle::ast2ram
Definition: AstToRamTranslator.cpp:132
SignedConstant.h
souffle::ast::analysis::AuxiliaryArityAnalysis::getArity
size_t getArity(const Atom *atom) const
Returns the number of auxiliary parameters of an atom's relation.
Definition: AuxArity.h:59
Clause.h
souffle::ast2ram::AstToRamTranslator::ioType
const ast::analysis::IOTypeAnalysis * ioType
IO Type.
Definition: AstToRamTranslator.h:130
souffle::RamUnsignedFromString
RamUnsigned RamUnsignedFromString(const std::string &str, std::size_t *position=nullptr, const int base=10)
Converts a string to a RamUnsigned.
Definition: StringUtil.h:110
souffle::ast::analysis::AuxiliaryArityAnalysis
Determine the auxiliary arity for relations.
Definition: AuxArity.h:38
souffle::ast::UnnamedVariable
Unnamed variable class.
Definition: UnnamedVariable.h:34
SubroutineReturn.h
Counter.h
souffle::ast::getAtomRelation
const Relation * getAtomRelation(const Atom *atom, const Program *program)
Returns the relation referenced by the given atom.
Definition: Utils.cpp:129
BinaryConstraint.h
souffle::ast::analysis::RecursiveClausesAnalysis
Analysis pass identifying clauses which are recursive.
Definition: RecursiveClauses.h:44
souffle::ast::visitDepthFirst
void visitDepthFirst(const Node &root, Visitor< R, Ps... > &visitor, Args &... args)
A utility function visiting all nodes within the ast rooted by the given node recursively in a depth-...
Definition: Visitor.h:273
souffle::ast::analysis::RecursiveClausesAnalysis::recursive
bool recursive(const Clause *clause) const
Definition: RecursiveClauses.h:54
souffle::ast2ram::AstToRamTranslator::translateConstant
Own< ram::Expression > translateConstant(ast::Constant const &c)
translate RAM code for a constant value
Definition: AstToRamTranslator.cpp:437
Expression.h
souffle::LogStatement::tRelationSaveTime
static const std::string tRelationSaveTime(const std::string &relationName, const SrcLocation &srcLocation)
Definition: LogStatement.h:52
UndefValue.h
souffle::ast::analysis::getTypeQualifier
std::string getTypeQualifier(const Type &type)
Returns full type qualifier for a given type.
Definition: TypeSystem.cpp:204
Loop.h
FunctionalUtil.h
souffle::RamFloatFromString
RamFloat RamFloatFromString(const std::string &str, std::size_t *position=nullptr)
Converts a string to a RamFloat.
Definition: StringUtil.h:93
souffle::ast::NumericConstant::Type::Float
@ Float
ClauseTranslator.h
souffle::ast::NumericConstant
Numeric Constant.
Definition: NumericConstant.h:43
souffle::TypeAttribute::Float
@ Float
souffle::ast::QualifiedName
Qualified Name class defines fully/partially qualified names to identify objects in components.
Definition: QualifiedName.h:39
rel
void rel(size_t limit, bool showLimit=true)
Definition: Tui.h:1086
souffle::ast::analysis::FunctorAnalysis::isStateful
bool isStateful(const UserDefinedFunctor *udf) const
Return whether a UDF is stateful.
Definition: Functor.cpp:36
TypeEnvironment.h
souffle::ErrorReport
Definition: ErrorReport.h:152
LogSize.h
souffle::VecOwn
std::vector< Own< A > > VecOwn
Definition: ContainerUtil.h:45
ErrorReport.h
souffle::ast2ram::AstToRamTranslator::getOutputDirectives
std::vector< std::map< std::string, std::string > > getOutputDirectives(const ast::Relation *rel)
Definition: AstToRamTranslator.cpp:194
RecordInit.h
NumericConstant.h
IntrinsicOperator.h
FloatConstant.h
std::type
ElementType type
Definition: span.h:640
TypeAttribute.h
Variable.h
Parallel.h
TypeSystem.h
Conjunction.h
souffle::ast2ram::Location::identifier
const int identifier
Definition: Location.h:34
souffle::ast2ram::AstToRamTranslator::translateRecursiveRelation
Own< ram::Statement > translateRecursiveRelation(const std::set< const ast::Relation * > &scc, const ast::analysis::RecursiveClausesAnalysis *recursiveClauses)
translate RAM code for recursive relations in a strongly-connected component
Definition: AstToRamTranslator.cpp:554
souffle::ast::Argument::clone
Argument * clone() const override=0
Create clone.
Extend.h