103 #include <functional> 
  110 #include <type_traits> 
  118 using ram::analysis::IndexAnalysis;
 
  120 using namespace stream_write_qualified_char_as_number;
 
  125     auto pos = idxMap.find(txt);
 
  126     if (pos == idxMap.end()) {
 
  127         return idxMap[txt] = ctr++;
 
  135     std::string modifiedTxt = txt;
 
  136     std::replace(modifiedTxt.begin(), modifiedTxt.end(), 
'-', 
'.');
 
  137     static unsigned counter;
 
  138     auto pos = neIdxMap.find(modifiedTxt);
 
  139     if (pos == neIdxMap.end()) {
 
  140         return neIdxMap[modifiedTxt] = counter++;
 
  142         return neIdxMap[modifiedTxt];
 
  148     auto it = identifiers.find(name);
 
  149     if (it != identifiers.end()) {
 
  154     for (
i = 0; 
i < name.length(); ++
i) {
 
  155         if ((isalnum(name.at(
i)) != 0) || name.at(
i) == 
'_') {
 
  160     for (
auto ch : std::to_string(identifiers.size() + 1) + 
'_' + name.substr(
i)) {
 
  162         if (isalnum(ch) != 0) {
 
  168         else if (
id.empty() || 
id.back() != 
'_') {
 
  174     id = 
id.substr(0, 1024);
 
  175     identifiers.insert(std::make_pair(name, 
id));
 
  181     return "rel_" + convertRamIdent(
rel.getName());
 
  185     return "rel_" + convertRamIdent(
rel->getName());
 
  190     return getRelationName(
rel) + 
"_op_ctxt";
 
  196     if (typeCache.find(relationType->getTypeName()) != typeCache.end()) {
 
  199     typeCache.insert(relationType->getTypeName());
 
  202     relationType->generateTypeStruct(out);
 
  207     std::set<const ram::Relation*> res;
 
  210             res.insert(lookup(scan->getRelation()));
 
  211         } 
else if (
auto agg = 
dynamic_cast<const Aggregate*
>(&node)) {
 
  212             res.insert(lookup(agg->getRelation()));
 
  213         } 
else if (
auto exists = 
dynamic_cast<const ExistenceCheck*
>(&node)) {
 
  214             res.insert(lookup(exists->getRelation()));
 
  215         } 
else if (
auto provExists = 
dynamic_cast<const ProvenanceExistenceCheck*
>(&node)) {
 
  216             res.insert(lookup(provExists->getRelation()));
 
  217         } 
else if (
auto project = 
dynamic_cast<const Project*
>(&node)) {
 
  218             res.insert(lookup(project->getRelation()));
 
  225     class CodeEmitter : 
public Visitor<void, std::ostream&> {
 
  227         Synthesiser& synthesiser;
 
  228         IndexAnalysis* 
const isa = synthesiser.getTranslationUnit().getAnalysis<IndexAnalysis>();
 
  231 #ifndef PRINT_BEGIN_COMMENT 
  232 #define PRINT_BEGIN_COMMENT(os)                                                  \ 
  233     if (Global::config().has("debug-report") || Global::config().has("verbose")) \ 
  237 #ifndef PRINT_END_COMMENT 
  238 #define PRINT_END_COMMENT(os)                                                    \ 
  239     if (Global::config().has("debug-report") || Global::config().has("verbose")) \ 
  244         std::function<void(std::ostream&, 
const Expression*)> rec;
 
  245         std::function<void(std::ostream&, 
const Expression*)> recWithDefault;
 
  247         std::ostringstream preamble;
 
  248         bool preambleIssued = 
false;
 
  252             rec = [&](
auto& out, 
const auto* value) {
 
  253                 out << 
"ramBitCast(";
 
  257             recWithDefault = [&](
auto& out, 
const auto* value) {
 
  266         std::pair<std::stringstream, std::stringstream> getPaddedRangeBounds(
const ram::Relation& 
rel,
 
  267                 const std::vector<Expression*>& rangePatternLower,
 
  268                 const std::vector<Expression*>& rangePatternUpper) {
 
  269             std::stringstream 
low;
 
  270             std::stringstream 
high;
 
  273             size_t realArity = 
rel.getArity();
 
  274             size_t arity = rangePatternLower.size();
 
  276             low << 
"Tuple<RamDomain," << realArity << 
">{{";
 
  277             high << 
"Tuple<RamDomain," << realArity << 
">{{";
 
  279             for (
size_t column = 0; column < arity; column++) {
 
  280                 std::string supremum;
 
  283                 switch (
rel.getAttributeTypes()[column][0]) {
 
  285                         supremum = 
"ramBitCast<RamDomain>(MIN_RAM_FLOAT)";
 
  286                         infimum = 
"ramBitCast<RamDomain>(MAX_RAM_FLOAT)";
 
  289                         supremum = 
"ramBitCast<RamDomain>(MIN_RAM_UNSIGNED)";
 
  290                         infimum = 
"ramBitCast<RamDomain>(MAX_RAM_UNSIGNED)";
 
  293                         supremum = 
"ramBitCast<RamDomain>(MIN_RAM_SIGNED)";
 
  294                         infimum = 
"ramBitCast<RamDomain>(MAX_RAM_SIGNED)";
 
  306                     low << 
"ramBitCast(";
 
  307                     visit(rangePatternLower[column], 
low);
 
  314                     high << 
"ramBitCast(";
 
  315                     visit(rangePatternUpper[column], 
high);
 
  322             return std::make_pair(std::move(
low), std::move(
high));
 
  327         void visitIO(
const IO& io, std::ostream& out)
 override {
 
  331             auto printDirectives = [&](
const std::map<std::string, std::string>& registry) {
 
  332                 auto cur = registry.begin();
 
  333                 if (cur == registry.end()) {
 
  336                 out << 
"{{\"" << cur->first << 
"\",\"" << 
escape(cur->second) << 
"\"}";
 
  338                 for (; cur != registry.end(); ++cur) {
 
  339                     out << 
",{\"" << cur->first << 
"\",\"" << 
escape(cur->second) << 
"\"}";
 
  345             const std::string& op = io.get(
"operation");
 
  346             out << 
"if (performIO) {\n";
 
  351                 out << 
"std::map<std::string, std::string> directiveMap(";
 
  354                 out << R
"_(if (!inputDirectory.empty()) {)_"; 
  355                 out << R"_(directiveMap["fact-dir"] = inputDirectory;)_"; 
  357                 out << 
"IOSystem::getInstance().getReader(";
 
  358                 out << 
"directiveMap, symTable, recordTable";
 
  359                 out << 
")->readAll(*" << synthesiser.getRelationName(synthesiser.lookup(io.getRelation()));
 
  361                 out << 
"} catch (std::exception& e) {std::cerr << \"Error loading data: \" << e.what() " 
  364             } 
else if (op == 
"output" || op == 
"printsize") {
 
  366                 out << 
"std::map<std::string, std::string> directiveMap(";
 
  369                 out << R
"_(if (!outputDirectory.empty()) {)_"; 
  370                 out << R"_(directiveMap["output-dir"] = outputDirectory;)_"; 
  372                 out << 
"IOSystem::getInstance().getWriter(";
 
  373                 out << 
"directiveMap, symTable, recordTable";
 
  374                 out << 
")->writeAll(*" << synthesiser.getRelationName(synthesiser.lookup(io.getRelation()))
 
  376                 out << 
"} catch (std::exception& e) {std::cerr << e.what();exit(1);}\n";
 
  378                 assert(
"Wrong i/o operation");
 
  384         void visitQuery(
const Query& query, std::ostream& out)
 override {
 
  390             const Operation* next = &query.getOperation();
 
  391             VecOwn<Condition> requireCtx;
 
  392             VecOwn<Condition> freeOfCtx;
 
  393             if (
const auto* 
filter = 
dynamic_cast<const Filter*
>(&query.getOperation())) {
 
  394                 next = &
filter->getOperation();
 
  398                 for (
auto const& cur : conditions) {
 
  399                     bool needContext = 
false;
 
  400                     visitDepthFirst(*cur, [&](
const ExistenceCheck&) { needContext = 
true; });
 
  401                     visitDepthFirst(*cur, [&](
const ProvenanceExistenceCheck&) { needContext = 
true; });
 
  409                 if (freeOfCtx.size() > 0) {
 
  422             bool isParallel = 
false;
 
  423             visitDepthFirst(*next, [&](
const AbstractParallel&) { isParallel = 
true; });
 
  428             preambleIssued = 
false;
 
  431             for (
const ram::Relation* 
rel : synthesiser.getReferencedRelations(query.getOperation())) {
 
  432                 preamble << 
"CREATE_OP_CONTEXT(" << synthesiser.getOpContextName(*
rel);
 
  433                 preamble << 
"," << synthesiser.getRelationName(*
rel);
 
  434                 preamble << 
"->createContext());\n";
 
  439                 if (requireCtx.size() > 0) {
 
  449                 out << preamble.str();
 
  450                 if (requireCtx.size() > 0) {
 
  462                 out << 
"PARALLEL_END\n";  
 
  468             if (freeOfCtx.size() > 0) {
 
  475         void visitClear(
const Clear& clear, std::ostream& out)
 override {
 
  478             if (!synthesiser.lookup(clear.getRelation())->isTemp()) {
 
  479                 out << 
"if (performIO) ";
 
  481             out << synthesiser.getRelationName(synthesiser.lookup(clear.getRelation())) << 
"->" 
  487         void visitLogSize(
const LogSize& 
size, std::ostream& out)
 override {
 
  489             out << 
"ProfileEventSingleton::instance().makeQuantityEvent( R\"(";
 
  490             out << 
size.getMessage() << 
")\",";
 
  491             out << synthesiser.getRelationName(synthesiser.lookup(
size.getRelation())) << 
"->size(),iter);";
 
  497         void visitSequence(
const Sequence& seq, std::ostream& out)
 override {
 
  499             for (
const auto& cur : seq.getStatements()) {
 
  505         void visitParallel(
const Parallel& parallel, std::ostream& out)
 override {
 
  507             auto stmts = parallel.getStatements();
 
  516             if (stmts.size() == 1) {
 
  517                 visit(stmts[0], out);
 
  525             out << 
"SECTIONS_START;\n";
 
  528             for (
const auto& cur : stmts) {
 
  529                 out << 
"SECTION_START;\n";
 
  531                 out << 
"SECTION_END\n";
 
  535             out << 
"SECTIONS_END;\n";
 
  539         void visitLoop(
const Loop& loop, std::ostream& out)
 override {
 
  541             out << 
"iter = 0;\n";
 
  542             out << 
"for(;;) {\n";
 
  543             visit(loop.getBody(), out);
 
  546             out << 
"iter = 0;\n";
 
  550         void visitSwap(
const Swap& swap, std::ostream& out)
 override {
 
  552             const std::string& deltaKnowledge =
 
  553                     synthesiser.getRelationName(synthesiser.lookup(swap.getFirstRelation()));
 
  554             const std::string& newKnowledge =
 
  555                     synthesiser.getRelationName(synthesiser.lookup(swap.getSecondRelation()));
 
  557             out << 
"std::swap(" << deltaKnowledge << 
", " << newKnowledge << 
");\n";
 
  561         void visitExtend(
const Extend& extend, std::ostream& out)
 override {
 
  563             out << synthesiser.getRelationName(synthesiser.lookup(extend.getSourceRelation())) << 
"->" 
  565                 << 
"*" << synthesiser.getRelationName(synthesiser.lookup(extend.getTargetRelation()))
 
  570         void visitExit(
const Exit& exit, std::ostream& out)
 override {
 
  573             visit(exit.getCondition(), out);
 
  578         void visitCall(
const Call& call, std::ostream& out)
 override {
 
  580             const Program& prog = synthesiser.getTranslationUnit().getProgram();
 
  581             const auto& subs = prog.getSubroutines();
 
  583             out << 
" std::vector<RamDomain> args, ret;\n";
 
  584             out << 
"subroutine_" << distance(subs.begin(), subs.find(call.getName())) << 
"(args, ret);\n";
 
  589         void visitLogRelationTimer(
const LogRelationTimer& timer, std::ostream& out)
 override {
 
  596             const auto* 
rel = synthesiser.lookup(timer.getRelation());
 
  597             auto relName = synthesiser.getRelationName(
rel);
 
  599             out << 
"\tLogger logger(R\"_(" << timer.getMessage() << 
")_\",iter, [&](){return " << relName
 
  602             visit(timer.getStatement(), out);
 
  609         void visitLogTimer(
const LogTimer& timer, std::ostream& out)
 override {
 
  617             out << 
"\tLogger logger(R\"_(" << timer.getMessage() << 
")_\",iter);\n";
 
  619             visit(timer.getStatement(), out);
 
  626         void visitDebugInfo(
const DebugInfo& dbg, std::ostream& out)
 override {
 
  628             out << 
"signalHandler->setMsg(R\"_(";
 
  629             out << dbg.getMessage();
 
  633             visit(dbg.getStatement(), out);
 
  639         void visitNestedOperation(
const NestedOperation& nested, std::ostream& out)
 override {
 
  640             visit(nested.getOperation(), out);
 
  641             if (
Global::config().has(
"profile") && !nested.getProfileText().empty()) {
 
  642                 out << 
"freqs[" << synthesiser.lookupFreqIdx(nested.getProfileText()) << 
"]++;\n";
 
  646         void visitTupleOperation(
const TupleOperation& search, std::ostream& out)
 override {
 
  648             visitNestedOperation(search, out);
 
  652         void visitParallelScan(
const ParallelScan& pscan, std::ostream& out)
 override {
 
  653             const auto* 
rel = synthesiser.lookup(pscan.getRelation());
 
  654             const auto& relName = synthesiser.getRelationName(
rel);
 
  656             assert(pscan.getTupleId() == 0 && 
"not outer-most loop");
 
  658             assert(
rel->getArity() > 0 && 
"AstToRamTranslator failed/no parallel scans for nullaries");
 
  660             assert(!preambleIssued && 
"only first loop can be made parallel");
 
  661             preambleIssued = 
true;
 
  665             out << 
"auto part = " << relName << 
"->partition();\n";
 
  666             out << 
"PARALLEL_START\n";
 
  667             out << preamble.str();
 
  668             out << 
"pfor(auto it = part.begin(); it<part.end();++it){\n";
 
  670             out << 
"for(const auto& env0 : *it) {\n";
 
  672             visitTupleOperation(pscan, out);
 
  675             out << 
"} catch(std::exception &e) { signalHandler->error(e.what());}\n";
 
  681         void visitScan(
const Scan& scan, std::ostream& out)
 override {
 
  682             const auto* 
rel = synthesiser.lookup(scan.getRelation());
 
  683             auto relName = synthesiser.getRelationName(
rel);
 
  684             auto id = scan.getTupleId();
 
  688             assert(
rel->getArity() > 0 && 
"AstToRamTranslator failed/no scans for nullaries");
 
  690             out << 
"for(const auto& env" << 
id << 
" : " 
  691                 << 
"*" << relName << 
") {\n";
 
  693             visitTupleOperation(scan, out);
 
  700         void visitChoice(
const Choice& choice, std::ostream& out)
 override {
 
  701             const auto* 
rel = synthesiser.lookup(choice.getRelation());
 
  702             auto relName = synthesiser.getRelationName(
rel);
 
  705             assert(
rel->getArity() > 0 && 
"AstToRamTranslator failed/no choice for nullaries");
 
  709             out << 
"for(const auto& env" << 
identifier << 
" : " 
  710                 << 
"*" << relName << 
") {\n";
 
  713             visit(choice.getCondition(), out);
 
  717             visitTupleOperation(choice, out);
 
  726         void visitParallelChoice(
const ParallelChoice& pchoice, std::ostream& out)
 override {
 
  727             const auto* 
rel = synthesiser.lookup(pchoice.getRelation());
 
  728             auto relName = synthesiser.getRelationName(
rel);
 
  730             assert(pchoice.getTupleId() == 0 && 
"not outer-most loop");
 
  732             assert(
rel->getArity() > 0 && 
"AstToRamTranslator failed/no parallel choice for nullaries");
 
  734             assert(!preambleIssued && 
"only first loop can be made parallel");
 
  735             preambleIssued = 
true;
 
  739             out << 
"auto part = " << relName << 
"->partition();\n";
 
  740             out << 
"PARALLEL_START\n";
 
  741             out << preamble.str();
 
  742             out << 
"pfor(auto it = part.begin(); it<part.end();++it){\n";
 
  744             out << 
"for(const auto& env0 : *it) {\n";
 
  747             visit(pchoice.getCondition(), out);
 
  751             visitTupleOperation(pchoice, out);
 
  756             out << 
"} catch(std::exception &e) { signalHandler->error(e.what());}\n";
 
  762         void visitIndexScan(
const IndexScan& iscan, std::ostream& out)
 override {
 
  763             const auto* 
rel = synthesiser.lookup(iscan.getRelation());
 
  764             auto relName = synthesiser.getRelationName(
rel);
 
  766             auto keys = isa->getSearchSignature(&iscan);
 
  767             auto arity = 
rel->getArity();
 
  769             const auto& rangePatternLower = iscan.getRangePattern().first;
 
  770             const auto& rangePatternUpper = iscan.getRangePattern().second;
 
  772             assert(arity > 0 && 
"AstToRamTranslator failed/no index scans for nullaries");
 
  775             auto ctxName = 
"READ_OP_CONTEXT(" + synthesiser.getOpContextName(*
rel) + 
")";
 
  776             auto rangeBounds = getPaddedRangeBounds(*
rel, rangePatternLower, rangePatternUpper);
 
  778             out << 
"auto range = " << relName << 
"->" 
  779                 << 
"lowerUpperRange_" << keys << 
"(" << rangeBounds.first.str() << 
"," 
  780                 << rangeBounds.second.str() << 
"," << ctxName << 
");\n";
 
  781             out << 
"for(const auto& env" << 
identifier << 
" : range) {\n";
 
  783             visitTupleOperation(iscan, out);
 
  789         void visitParallelIndexScan(
const ParallelIndexScan& piscan, std::ostream& out)
 override {
 
  790             const auto* 
rel = synthesiser.lookup(piscan.getRelation());
 
  791             auto relName = synthesiser.getRelationName(
rel);
 
  792             auto arity = 
rel->getArity();
 
  793             auto keys = isa->getSearchSignature(&piscan);
 
  795             const auto& rangePatternLower = piscan.getRangePattern().first;
 
  796             const auto& rangePatternUpper = piscan.getRangePattern().second;
 
  798             assert(piscan.getTupleId() == 0 && 
"not outer-most loop");
 
  800             assert(arity > 0 && 
"AstToRamTranslator failed/no parallel index scan for nullaries");
 
  802             assert(!preambleIssued && 
"only first loop can be made parallel");
 
  803             preambleIssued = 
true;
 
  806             auto rangeBounds = getPaddedRangeBounds(*
rel, rangePatternLower, rangePatternUpper);
 
  807             out << 
"auto range = " << relName
 
  810                 << 
"lowerUpperRange_" << keys << 
"(" << rangeBounds.first.str() << 
"," 
  811                 << rangeBounds.second.str() << 
");\n";
 
  812             out << 
"auto part = range.partition();\n";
 
  813             out << 
"PARALLEL_START\n";
 
  814             out << preamble.str();
 
  815             out << 
"pfor(auto it = part.begin(); it<part.end(); ++it) { \n";
 
  817             out << 
"for(const auto& env0 : *it) {\n";
 
  819             visitTupleOperation(piscan, out);
 
  822             out << 
"} catch(std::exception &e) { signalHandler->error(e.what());}\n";
 
  828         void visitIndexChoice(
const IndexChoice& ichoice, std::ostream& out)
 override {
 
  830             const auto* 
rel = synthesiser.lookup(ichoice.getRelation());
 
  831             auto relName = synthesiser.getRelationName(
rel);
 
  833             auto arity = 
rel->getArity();
 
  834             const auto& rangePatternLower = ichoice.getRangePattern().first;
 
  835             const auto& rangePatternUpper = ichoice.getRangePattern().second;
 
  836             auto keys = isa->getSearchSignature(&ichoice);
 
  839             assert(arity > 0 && 
"AstToRamTranslator failed");
 
  840             auto ctxName = 
"READ_OP_CONTEXT(" + synthesiser.getOpContextName(*
rel) + 
")";
 
  841             auto rangeBounds = getPaddedRangeBounds(*
rel, rangePatternLower, rangePatternUpper);
 
  843             out << 
"auto range = " << relName << 
"->" 
  844                 << 
"lowerUpperRange_" << keys << 
"(" << rangeBounds.first.str() << 
"," 
  845                 << rangeBounds.second.str() << 
"," << ctxName << 
");\n";
 
  846             out << 
"for(const auto& env" << 
identifier << 
" : range) {\n";
 
  849             visit(ichoice.getCondition(), out);
 
  853             visitTupleOperation(ichoice, out);
 
  862         void visitParallelIndexChoice(
const ParallelIndexChoice& pichoice, std::ostream& out)
 override {
 
  864             const auto* 
rel = synthesiser.lookup(pichoice.getRelation());
 
  865             auto relName = synthesiser.getRelationName(
rel);
 
  866             auto arity = 
rel->getArity();
 
  867             const auto& rangePatternLower = pichoice.getRangePattern().first;
 
  868             const auto& rangePatternUpper = pichoice.getRangePattern().second;
 
  869             auto keys = isa->getSearchSignature(&pichoice);
 
  871             assert(pichoice.getTupleId() == 0 && 
"not outer-most loop");
 
  873             assert(arity > 0 && 
"AstToRamTranslator failed");
 
  875             assert(!preambleIssued && 
"only first loop can be made parallel");
 
  876             preambleIssued = 
true;
 
  879             auto rangeBounds = getPaddedRangeBounds(*
rel, rangePatternLower, rangePatternUpper);
 
  880             out << 
"auto range = " << relName
 
  883                 << 
"lowerUpperRange_" << keys << 
"(" << rangeBounds.first.str() << 
"," 
  884                 << rangeBounds.second.str() << 
");\n";
 
  885             out << 
"auto part = range.partition();\n";
 
  886             out << 
"PARALLEL_START\n";
 
  887             out << preamble.str();
 
  888             out << 
"pfor(auto it = part.begin(); it<part.end(); ++it) { \n";
 
  890             out << 
"for(const auto& env0 : *it) {\n";
 
  893             visit(pichoice.getCondition(), out);
 
  897             visitTupleOperation(pichoice, out);
 
  902             out << 
"} catch(std::exception &e) { signalHandler->error(e.what());}\n";
 
  908         void visitUnpackRecord(
const UnpackRecord& unpack, std::ostream& out)
 override {
 
  910             auto arity = unpack.getArity();
 
  913             out << 
"RamDomain const ref = ";
 
  914             visit(unpack.getExpression(), out);
 
  918             out << 
"if (ref == 0) continue;\n";
 
  921             out << 
"const RamDomain *" 
  922                 << 
"env" << unpack.getTupleId() << 
" = " 
  923                 << 
"recordTable.unpack(ref," << arity << 
");" 
  929             visitTupleOperation(unpack, out);
 
  935         void visitParallelIndexAggregate(
 
  936                 const ParallelIndexAggregate& aggregate, std::ostream& out)
 override {
 
  937             assert(aggregate.getTupleId() == 0 && 
"not outer-most loop");
 
  938             assert(!preambleIssued && 
"only first loop can be made parallel");
 
  939             preambleIssued = 
true;
 
  942             const auto* 
rel = synthesiser.lookup(aggregate.getRelation());
 
  943             auto arity = 
rel->getArity();
 
  944             auto relName = synthesiser.getRelationName(
rel);
 
  945             auto ctxName = 
"READ_OP_CONTEXT(" + synthesiser.getOpContextName(*
rel) + 
")";
 
  949             std::string tuple_type = 
"Tuple<RamDomain," + 
toString(arity) + 
">";
 
  952             out << 
"Tuple<RamDomain,1> env" << 
identifier << 
";\n";
 
  955             auto keys = isa->getSearchSignature(&aggregate);
 
  959                     isTrue(&aggregate.getCondition())) {
 
  961                 out << 
"env" << 
identifier << 
"[0] = " << relName << 
"->" 
  964                 out << preamble.str();
 
  965                 visitTupleOperation(aggregate, out);
 
  970             out << 
"bool shouldRunNested = false;\n";
 
  974             switch (aggregate.getFunction()) {
 
  983                     out << 
"shouldRunNested = true;\n";
 
  990                     out << 
"shouldRunNested = true;\n";
 
  996             switch (aggregate.getFunction()) {
 
 1019                 default: 
fatal(
"Unhandled aggregate operation");
 
 1022             std::string sharedVariable = 
"res0";
 
 1034             out << 
type << 
" res0 = " << init << 
";\n";
 
 1036                 out << 
"RamUnsigned res1 = 0;\n";
 
 1037                 sharedVariable += 
", res1";
 
 1040             out << preamble.str();
 
 1041             out << 
"PARALLEL_START\n";
 
 1044                 out << 
"#pragma omp for reduction(" << op << 
":" << sharedVariable << 
")\n";
 
 1045                 out << 
"for(const auto& env" << 
identifier << 
" : " 
 1046                     << 
"*" << relName << 
") {\n";
 
 1048                 const auto& rangePatternLower = aggregate.getRangePattern().first;
 
 1049                 const auto& rangePatternUpper = aggregate.getRangePattern().second;
 
 1051                 auto rangeBounds = getPaddedRangeBounds(*
rel, rangePatternLower, rangePatternUpper);
 
 1052                 out << 
"auto range = " << relName << 
"->" 
 1053                     << 
"lowerUpperRange_" << keys << 
"(" << rangeBounds.first.str() << 
"," 
 1054                     << rangeBounds.second.str() << 
"," << ctxName << 
");\n";
 
 1056                 out << 
"auto part = range.partition();\n";
 
 1057                 out << 
"#pragma omp for reduction(" << op << 
":" << sharedVariable << 
")\n";
 
 1059                 out << 
"for (auto it = part.begin(); it < part.end(); ++it) {\n";
 
 1061                 out << 
"for (const auto& env" << 
identifier << 
": *it) {\n";
 
 1066             visit(aggregate.getCondition(), out);
 
 1069             out << 
"shouldRunNested = true;\n";
 
 1072             switch (aggregate.getFunction()) {
 
 1076                     out << 
"res0 = std::min(res0,ramBitCast<" << 
type << 
">(";
 
 1077                     visit(aggregate.getExpression(), out);
 
 1083                     out << 
"res0 = std::max(res0,ramBitCast<" << 
type << 
">(";
 
 1084                     visit(aggregate.getExpression(), out);
 
 1092                         << 
"ramBitCast<" << 
type << 
">(";
 
 1093                     visit(aggregate.getExpression(), out);
 
 1099                         << 
"ramBitCast<RamFloat>(";
 
 1100                     visit(aggregate.getExpression(), out);
 
 1113             if (!keys.empty()) {
 
 1118             out << 
"#pragma omp single\n{\n";
 
 1121                 out << 
"if (res1 != 0) {\n";
 
 1122                 out << 
"res0 = res0 / res1;\n";
 
 1127             out << 
"env" << 
identifier << 
"[0] = ramBitCast(res0);\n";
 
 1130             out << 
"if (shouldRunNested) {\n";
 
 1131             visitTupleOperation(aggregate, out);
 
 1138         bool isGuaranteedToBeMinimum(
const IndexAggregate& aggregate) {
 
 1140             auto keys = isa->getSearchSignature(&aggregate);
 
 1143             const auto* tupleElem = 
dynamic_cast<const TupleElement*
>(&aggregate.getExpression());
 
 1144             return tupleElem && tupleElem->getTupleId() == 
identifier &&
 
 1149         void visitIndexAggregate(
const IndexAggregate& aggregate, std::ostream& out)
 override {
 
 1152             const auto* 
rel = synthesiser.lookup(aggregate.getRelation());
 
 1153             auto arity = 
rel->getArity();
 
 1154             auto relName = synthesiser.getRelationName(
rel);
 
 1155             auto ctxName = 
"READ_OP_CONTEXT(" + synthesiser.getOpContextName(*
rel) + 
")";
 
 1159             std::string tuple_type = 
"Tuple<RamDomain," + 
toString(arity) + 
">";
 
 1162             out << 
"Tuple<RamDomain,1> env" << 
identifier << 
";\n";
 
 1165             auto keys = isa->getSearchSignature(&aggregate);
 
 1169                     isTrue(&aggregate.getCondition())) {
 
 1171                 out << 
"env" << 
identifier << 
"[0] = " << relName << 
"->" 
 1173                 visitTupleOperation(aggregate, out);
 
 1178             out << 
"bool shouldRunNested = false;\n";
 
 1182             switch (aggregate.getFunction()) {
 
 1191                     out << 
"shouldRunNested = true;\n";
 
 1198                     out << 
"shouldRunNested = true;\n";
 
 1212             out << 
type << 
" res0 = " << init << 
";\n";
 
 1215                 out << 
"RamUnsigned res1 = 0;\n";
 
 1220                 out << 
"for(const auto& env" << 
identifier << 
" : " 
 1221                     << 
"*" << relName << 
") {\n";
 
 1223                 const auto& rangePatternLower = aggregate.getRangePattern().first;
 
 1224                 const auto& rangePatternUpper = aggregate.getRangePattern().second;
 
 1226                 auto rangeBounds = getPaddedRangeBounds(*
rel, rangePatternLower, rangePatternUpper);
 
 1228                 out << 
"auto range = " << relName << 
"->" 
 1229                     << 
"lowerUpperRange_" << keys << 
"(" << rangeBounds.first.str() << 
"," 
 1230                     << rangeBounds.second.str() << 
"," << ctxName << 
");\n";
 
 1233                 out << 
"for(const auto& env" << 
identifier << 
" : range) {\n";
 
 1238             visit(aggregate.getCondition(), out);
 
 1241             out << 
"shouldRunNested = true;\n";
 
 1244             switch (aggregate.getFunction()) {
 
 1248                     out << 
"res0 = std::min(res0,ramBitCast<" << 
type << 
">(";
 
 1249                     visit(aggregate.getExpression(), out);
 
 1251                     if (isGuaranteedToBeMinimum(aggregate)) {
 
 1258                     out << 
"res0 = std::max(res0,ramBitCast<" << 
type << 
">(";
 
 1259                     visit(aggregate.getExpression(), out);
 
 1267                         << 
"ramBitCast<" << 
type << 
">(";
 
 1268                     visit(aggregate.getExpression(), out);
 
 1274                         << 
"ramBitCast<RamFloat>(";
 
 1275                     visit(aggregate.getExpression(), out);
 
 1287                 out << 
"if (res1 != 0) {\n";
 
 1288                 out << 
"res0 = res0 / res1;\n";
 
 1293             out << 
"env" << 
identifier << 
"[0] = ramBitCast(res0);\n";
 
 1296             out << 
"if (shouldRunNested) {\n";
 
 1297             visitTupleOperation(aggregate, out);
 
 1303         void visitParallelAggregate(
const ParallelAggregate& aggregate, std::ostream& out)
 override {
 
 1306             const auto* 
rel = synthesiser.lookup(aggregate.getRelation());
 
 1307             auto relName = synthesiser.getRelationName(
rel);
 
 1308             auto ctxName = 
"READ_OP_CONTEXT(" + synthesiser.getOpContextName(*
rel) + 
")";
 
 1311             assert(aggregate.getTupleId() == 0 && 
"not outer-most loop");
 
 1312             assert(!preambleIssued && 
"only first loop can be made parallel");
 
 1313             preambleIssued = 
true;
 
 1316             out << 
"Tuple<RamDomain,1> env" << 
identifier << 
";\n";
 
 1321                 out << 
"env" << 
identifier << 
"[0] = " << relName << 
"->" 
 1323                 out << 
"PARALLEL_START\n";
 
 1324                 out << preamble.str();
 
 1325                 visitTupleOperation(aggregate, out);
 
 1330             out << 
"bool shouldRunNested = false;\n";
 
 1334             switch (aggregate.getFunction()) {
 
 1343                     out << 
"shouldRunNested = true;\n";
 
 1352                     out << 
"shouldRunNested = true;\n";
 
 1358             switch (aggregate.getFunction()) {
 
 1382                 default: 
fatal(
"Unhandled aggregate operation");
 
 1395             out << 
type << 
" res0 = " << init << 
";\n";
 
 1397             std::string sharedVariable = 
"res0";
 
 1399                 out << 
"RamUnsigned res1 = " << init << 
";\n";
 
 1400                 sharedVariable += 
", res1";
 
 1404             out << 
"auto part = " << relName << 
"->partition();\n";
 
 1405             out << 
"PARALLEL_START\n";
 
 1406             out << preamble.str();
 
 1408             out << 
"#pragma omp for reduction(" << op << 
":" << sharedVariable << 
")\n";
 
 1410             out << 
"for (auto it = part.begin(); it < part.end(); ++it) {\n";
 
 1412             out << 
"for (const auto& env" << 
identifier << 
": *it) {\n";
 
 1416             visit(aggregate.getCondition(), out);
 
 1419             out << 
"shouldRunNested = true;\n";
 
 1421             switch (aggregate.getFunction()) {
 
 1425                     out << 
"res0 = std::min(res0, ramBitCast<" << 
type << 
">(";
 
 1426                     visit(aggregate.getExpression(), out);
 
 1432                     out << 
"res0 = std::max(res0, ramBitCast<" << 
type << 
">(";
 
 1433                     visit(aggregate.getExpression(), out);
 
 1440                     out << 
"res0 += ramBitCast<" << 
type << 
">(";
 
 1441                     visit(aggregate.getExpression(), out);
 
 1446                     out << 
"res0 += ramBitCast<RamFloat>(";
 
 1447                     visit(aggregate.getExpression(), out);
 
 1461             out << 
"#pragma omp single\n{\n";
 
 1464                 out << 
"if (res1 != 0) {\n";
 
 1465                 out << 
"res0 = res0 / res1;\n";
 
 1470             out << 
"env" << 
identifier << 
"[0] = ramBitCast(res0);\n";
 
 1473             out << 
"if (shouldRunNested) {\n";
 
 1474             visitTupleOperation(aggregate, out);
 
 1479         void visitAggregate(
const Aggregate& aggregate, std::ostream& out)
 override {
 
 1482             const auto* 
rel = synthesiser.lookup(aggregate.getRelation());
 
 1483             auto relName = synthesiser.getRelationName(
rel);
 
 1484             auto ctxName = 
"READ_OP_CONTEXT(" + synthesiser.getOpContextName(*
rel) + 
")";
 
 1488             out << 
"Tuple<RamDomain,1> env" << 
identifier << 
";\n";
 
 1493                 out << 
"env" << 
identifier << 
"[0] = " << relName << 
"->" 
 1495                 visitTupleOperation(aggregate, out);
 
 1500             out << 
"bool shouldRunNested = false;\n";
 
 1504             switch (aggregate.getFunction()) {
 
 1513                     out << 
"shouldRunNested = true;\n";
 
 1522                     out << 
"shouldRunNested = true;\n";
 
 1535                 default: 
type = 
"RamDomain"; 
break;
 
 1537             out << 
type << 
" res0 = " << init << 
";\n";
 
 1540                 out << 
"RamUnsigned res1 = 0;\n";
 
 1544             out << 
"for(const auto& env" << 
identifier << 
" : " 
 1545                 << 
"*" << relName << 
") {\n";
 
 1549             visit(aggregate.getCondition(), out);
 
 1552             out << 
"shouldRunNested = true;\n";
 
 1554             switch (aggregate.getFunction()) {
 
 1558                     out << 
"res0 = std::min(res0, ramBitCast<" << 
type << 
">(";
 
 1559                     visit(aggregate.getExpression(), out);
 
 1565                     out << 
"res0 = std::max(res0,ramBitCast<" << 
type << 
">(";
 
 1566                     visit(aggregate.getExpression(), out);
 
 1574                         << 
"ramBitCast<" << 
type << 
">(";
 
 1576                     visit(aggregate.getExpression(), out);
 
 1582                         << 
"ramBitCast<RamFloat>(";
 
 1583                     visit(aggregate.getExpression(), out);
 
 1595                 out << 
"res0 = res0 / res1;\n";
 
 1599             out << 
"env" << 
identifier << 
"[0] = ramBitCast(res0);\n";
 
 1602             out << 
"if (shouldRunNested) {\n";
 
 1603             visitTupleOperation(aggregate, out);
 
 1609         void visitFilter(
const Filter& 
filter, std::ostream& out)
 override {
 
 1612             visit(
filter.getCondition(), out);
 
 1614             visitNestedOperation(
filter, out);
 
 1619         void visitBreak(
const Break& breakOp, std::ostream& out)
 override {
 
 1622             visit(breakOp.getCondition(), out);
 
 1623             out << 
") break;\n";
 
 1624             visitNestedOperation(breakOp, out);
 
 1628         void visitProject(
const Project& project, std::ostream& out)
 override {
 
 1630             const auto* 
rel = synthesiser.lookup(project.getRelation());
 
 1631             auto arity = 
rel->getArity();
 
 1632             auto relName = synthesiser.getRelationName(
rel);
 
 1633             auto ctxName = 
"READ_OP_CONTEXT(" + synthesiser.getOpContextName(*
rel) + 
")";
 
 1636             out << 
"Tuple<RamDomain," << arity << 
"> tuple{{" << 
join(project.getValues(), 
",", rec)
 
 1640             out << relName << 
"->" 
 1641                 << 
"insert(tuple," << ctxName << 
");\n";
 
 1648         void visitTrue(
const True&, std::ostream& out)
 override {
 
 1654         void visitFalse(
const False&, std::ostream& out)
 override {
 
 1660         void visitConjunction(
const Conjunction& conj, std::ostream& out)
 override {
 
 1662             visit(conj.getLHS(), out);
 
 1664             visit(conj.getRHS(), out);
 
 1668         void visitNegation(
const Negation& neg, std::ostream& out)
 override {
 
 1671             visit(neg.getOperand(), out);
 
 1676         void visitConstraint(
const Constraint& 
rel, std::ostream& out)
 override {
 
 1678 #define EVAL_CHILD(ty, idx)        \ 
 1679     out << "ramBitCast<" #ty ">("; \ 
 1680     visit(rel.idx(), out);         \ 
 1682 #define COMPARE_NUMERIC(ty, op) \ 
 1684     EVAL_CHILD(ty, getLHS);     \ 
 1685     out << " " #op " ";         \ 
 1686     EVAL_CHILD(ty, getRHS);     \ 
 1689 #define COMPARE_STRING(op)                \ 
 1690     out << "(symTable.resolve(";          \ 
 1691     EVAL_CHILD(RamDomain, getLHS);        \ 
 1692     out << ") " #op " symTable.resolve("; \ 
 1693     EVAL_CHILD(RamDomain, getRHS);        \ 
 1696 #define COMPARE_EQ_NE(opCode, op)                                         \ 
 1697     case BinaryConstraintOp::   opCode: COMPARE_NUMERIC(RamDomain  , op); \ 
 1698     case BinaryConstraintOp::F##opCode: COMPARE_NUMERIC(RamFloat   , op); 
 1699 #define COMPARE(opCode, op)                                               \ 
 1700     case BinaryConstraintOp::   opCode: COMPARE_NUMERIC(RamSigned  , op); \ 
 1701     case BinaryConstraintOp::U##opCode: COMPARE_NUMERIC(RamUnsigned, op); \ 
 1702     case BinaryConstraintOp::F##opCode: COMPARE_NUMERIC(RamFloat   , op); \ 
 1703     case BinaryConstraintOp::S##opCode: COMPARE_STRING(op); 
 1707             switch (
rel.getOperator()) {
 
 1719                     out << 
"regex_wrapper(symTable.resolve(";
 
 1720                     visit(
rel.getLHS(), out);
 
 1721                     out << 
"),symTable.resolve(";
 
 1722                     visit(
rel.getRHS(), out);
 
 1727                     out << 
"!regex_wrapper(symTable.resolve(";
 
 1728                     visit(
rel.getLHS(), out);
 
 1729                     out << 
"),symTable.resolve(";
 
 1730                     visit(
rel.getRHS(), out);
 
 1735                     out << 
"(symTable.resolve(";
 
 1736                     visit(
rel.getRHS(), out);
 
 1737                     out << 
").find(symTable.resolve(";
 
 1738                     visit(
rel.getLHS(), out);
 
 1739                     out << 
")) != std::string::npos)";
 
 1743                     out << 
"(symTable.resolve(";
 
 1744                     visit(
rel.getRHS(), out);
 
 1745                     out << 
").find(symTable.resolve(";
 
 1746                     visit(
rel.getLHS(), out);
 
 1747                     out << 
")) == std::string::npos)";
 
 1755 #undef COMPARE_NUMERIC 
 1756 #undef COMPARE_STRING 
 1758 #undef COMPARE_EQ_NE 
 1761         void visitEmptinessCheck(
const EmptinessCheck& emptiness, std::ostream& out)
 override {
 
 1763             out << synthesiser.getRelationName(synthesiser.lookup(emptiness.getRelation())) << 
"->" 
 1768         void visitRelationSize(
const RelationSize& 
size, std::ostream& out)
 override {
 
 1770             out << 
"(RamDomain)" << synthesiser.getRelationName(synthesiser.lookup(
size.getRelation()))
 
 1776         void visitExistenceCheck(
const ExistenceCheck& exists, std::ostream& out)
 override {
 
 1779             const auto* 
rel = synthesiser.lookup(exists.getRelation());
 
 1780             auto relName = synthesiser.getRelationName(
rel);
 
 1781             auto ctxName = 
"READ_OP_CONTEXT(" + synthesiser.getOpContextName(*
rel) + 
")";
 
 1782             auto arity = 
rel->getArity();
 
 1783             assert(arity > 0 && 
"AstToRamTranslator failed");
 
 1785             if (
Global::config().has(
"profile") && !synthesiser.lookup(exists.getRelation())->isTemp()) {
 
 1786                 out << R
"_((reads[)_" << synthesiser.lookupReadIdx(rel->getName()) << R"_(]++,)_"; 
 1791             if (isa->isTotalSignature(&exists)) {
 
 1792                 out << relName << 
"->" 
 1793                     << 
"contains(Tuple<RamDomain," << arity << 
">{{" << 
join(exists.getValues(), 
",", rec)
 
 1794                     << 
"}}," << ctxName << 
")" << after;
 
 1799             auto rangePatternLower = exists.getValues();
 
 1800             auto rangePatternUpper = exists.getValues();
 
 1802             auto rangeBounds = getPaddedRangeBounds(*
rel, rangePatternLower, rangePatternUpper);
 
 1804             out << 
"!" << relName << 
"->" 
 1805                 << 
"lowerUpperRange";
 
 1806             out << 
"_" << isa->getSearchSignature(&exists);
 
 1807             out << 
"(" << rangeBounds.first.str() << 
"," << rangeBounds.second.str() << 
"," << ctxName
 
 1808                 << 
").empty()" << after;
 
 1812         void visitProvenanceExistenceCheck(
 
 1813                 const ProvenanceExistenceCheck& provExists, std::ostream& out)
 override {
 
 1816             const auto* 
rel = synthesiser.lookup(provExists.getRelation());
 
 1817             auto relName = synthesiser.getRelationName(
rel);
 
 1818             auto ctxName = 
"READ_OP_CONTEXT(" + synthesiser.getOpContextName(*
rel) + 
")";
 
 1819             auto arity = 
rel->getArity();
 
 1820             auto auxiliaryArity = 
rel->getAuxiliaryArity();
 
 1823             out << 
"[&]() -> bool {\n";
 
 1824             out << 
"auto existenceCheck = " << relName << 
"->" 
 1825                 << 
"lowerUpperRange";
 
 1826             out << 
"_" << isa->getSearchSignature(&provExists);
 
 1829             size_t parts = arity - auxiliaryArity + 1;
 
 1833             auto vals = provExists.getValues();
 
 1836             for (
size_t i = 0; 
i < arity - auxiliaryArity; 
i++) {
 
 1838                         "ProvenanceExistenceCheck should always be specified for payload");
 
 1841             auto valsCopy = std::vector<Expression*>(vals.begin(), vals.begin() + parts);
 
 1842             auto rangeBounds = getPaddedRangeBounds(*
rel, valsCopy, valsCopy);
 
 1845             rangeBounds.first.seekp(-2, std::ios_base::end);
 
 1846             rangeBounds.second.seekp(-2, std::ios_base::end);
 
 1849             for (
size_t i = 0; 
i < auxiliaryArity - 2; 
i++) {
 
 1850                 rangeBounds.first << 
",ramBitCast<RamDomain, RamSigned>(MIN_RAM_SIGNED)";
 
 1851                 rangeBounds.second << 
",ramBitCast<RamDomain, RamSigned>(MAX_RAM_SIGNED)";
 
 1853             rangeBounds.first << 
",ramBitCast<RamDomain, RamSigned>(MIN_RAM_SIGNED)}}";
 
 1854             rangeBounds.second << 
",ramBitCast<RamDomain, RamSigned>(MAX_RAM_SIGNED)}}";
 
 1856             out << 
"(" << rangeBounds.first.str() << 
"," << rangeBounds.second.str() << 
"," << ctxName
 
 1858             out << 
"if (existenceCheck.empty()) return false; else return ((*existenceCheck.begin())[" 
 1859                 << arity - auxiliaryArity + 1 << 
"] <= ";
 
 1861             visit(*(provExists.getValues()[arity - auxiliaryArity + 1]), out);
 
 1868         void visitUnsignedConstant(
const UnsignedConstant& constant, std::ostream& out)
 override {
 
 1870             out << 
"RamUnsigned(" << constant.getValue() << 
")";
 
 1874         void visitFloatConstant(
const FloatConstant& constant, std::ostream& out)
 override {
 
 1876             out << 
"RamFloat(" << constant.getValue() << 
")";
 
 1880         void visitSignedConstant(
const SignedConstant& constant, std::ostream& out)
 override {
 
 1882             out << 
"RamSigned(" << constant.getConstant() << 
")";
 
 1886         void visitTupleElement(
const TupleElement& access, std::ostream& out)
 override {
 
 1888             out << 
"env" << access.getTupleId() << 
"[" << access.getElement() << 
"]";
 
 1892         void visitAutoIncrement(
const AutoIncrement& , std::ostream& out)
 override {
 
 1898         void visitIntrinsicOperator(
const IntrinsicOperator& op, std::ostream& out)
 override {
 
 1899 #define MINMAX_SYMBOL(op)                   \ 
 1901         out << "symTable.lookup(" #op "({"; \ 
 1902         for (auto& cur : args) {            \ 
 1903             out << "symTable.resolve(";     \ 
 1914 #define UNARY_OP(opcode, ty, op)                \ 
 1915     case FunctorOp::opcode: {                   \ 
 1916         out << "(" #op "(ramBitCast<" #ty ">("; \ 
 1917         visit(args[0], out);                    \ 
 1921 #define UNARY_OP_I(opcode, op) UNARY_OP(   opcode, RamSigned  , op) 
 1922 #define UNARY_OP_U(opcode, op) UNARY_OP(U##opcode, RamUnsigned, op) 
 1923 #define UNARY_OP_F(opcode, op) UNARY_OP(F##opcode, RamFloat   , op) 
 1924 #define UNARY_OP_INTEGRAL(opcode, op) \ 
 1925     UNARY_OP_I(opcode, op)            \ 
 1926     UNARY_OP_U(opcode, op) 
 1929 #define BINARY_OP_EXPR_EX(ty, op, rhs_post)      \ 
 1931         out << "(ramBitCast<" #ty ">(";          \ 
 1932         visit(args[0], out);                     \ 
 1933         out << ") " #op " ramBitCast<" #ty ">("; \ 
 1934         visit(args[1], out);                     \ 
 1935         out << rhs_post "))";                    \ 
 1938 #define BINARY_OP_EXPR(ty, op) BINARY_OP_EXPR_EX(ty, op, "") 
 1939 #define BINARY_OP_EXPR_SHIFT(ty, op) BINARY_OP_EXPR_EX(ty, op, " & RAM_BIT_SHIFT_MASK") 
 1940 #define BINARY_OP_EXPR_LOGICAL(ty, op) out << "RamDomain"; BINARY_OP_EXPR(ty, op) 
 1942 #define BINARY_OP_INTEGRAL(opcode, op)                         \ 
 1943     case FunctorOp::   opcode: BINARY_OP_EXPR(RamSigned  , op) \ 
 1944     case FunctorOp::U##opcode: BINARY_OP_EXPR(RamUnsigned, op) 
 1945 #define BINARY_OP_LOGICAL(opcode, op)                                  \ 
 1946     case FunctorOp::   opcode: BINARY_OP_EXPR_LOGICAL(RamSigned  , op) \ 
 1947     case FunctorOp::U##opcode: BINARY_OP_EXPR_LOGICAL(RamUnsigned, op) 
 1948 #define BINARY_OP_NUMERIC(opcode, op)                          \ 
 1949     BINARY_OP_INTEGRAL(opcode, op)                             \ 
 1950     case FunctorOp::F##opcode: BINARY_OP_EXPR(RamFloat   , op) 
 1951 #define BINARY_OP_BITWISE(opcode, op)                        \ 
 1952     case FunctorOp::   opcode:             \ 
 1953     case FunctorOp::U##opcode: BINARY_OP_EXPR(RamDomain, op) 
 1954 #define BINARY_OP_INTEGRAL_SHIFT(opcode, op, tySigned, tyUnsigned)  \ 
 1955     case FunctorOp::   opcode: BINARY_OP_EXPR_SHIFT(tySigned  , op) \ 
 1956     case FunctorOp::U##opcode: BINARY_OP_EXPR_SHIFT(tyUnsigned, op) 
 1958 #define BINARY_OP_EXP(opcode, ty, tyTemp)                                                     \ 
 1959     case FunctorOp::opcode: {                                                                 \ 
 1960         out << "static_cast<" #ty ">(static_cast<" #tyTemp ">(std::pow(ramBitCast<" #ty ">("; \ 
 1961         visit(args[0], out);                                                                  \ 
 1962         out << "), ramBitCast<" #ty ">(";                                                     \ 
 1963         visit(args[1], out);                                                                  \ 
 1968 #define NARY_OP(opcode, ty, op)            \ 
 1969     case FunctorOp::opcode: {              \ 
 1971         for (auto& cur : args) {           \ 
 1972             out << "ramBitCast<" #ty ">("; \ 
 1979 #define NARY_OP_ORDERED(opcode, op)     \ 
 1980     NARY_OP(   opcode, RamSigned  , op) \ 
 1981     NARY_OP(U##opcode, RamUnsigned, op) \ 
 1982     NARY_OP(F##opcode, RamFloat   , op) 
 1985 #define CONV_TO_STRING(opcode, ty)                \ 
 1986     case FunctorOp::opcode: {                     \ 
 1987         out << "symTable.lookup(std::to_string("; \ 
 1988         visit(args[0], out);                      \ 
 1991 #define CONV_FROM_STRING(opcode, ty)                                            \ 
 1992     case FunctorOp::opcode: {                                                   \ 
 1993         out << "souffle::evaluator::symbol2numeric<" #ty ">(symTable.resolve("; \ 
 1994         visit(args[0], out);                                                    \ 
 1999             auto args = op.getArguments();
 
 2000             switch (op.getOperator()) {
 
 2003                     visit(args[0], out);
 
 2008                     out << 
"static_cast<RamSigned>(symTable.resolve(";
 
 2009                     visit(args[0], out);
 
 2047 #if RAM_DOMAIN_SIZE == 32 
 2050 #elif RAM_DOMAIN_SIZE == 64 
 2054 #error "unhandled domain size" 
 2082                     out << 
"symTable.lookup(";
 
 2084                     while (
i < args.size() - 1) {
 
 2085                         out << 
"symTable.resolve(";
 
 2086                         visit(args[
i], out);
 
 2090                     out << 
"symTable.resolve(";
 
 2091                     visit(args[
i], out);
 
 2098                     out << 
"symTable.lookup(";
 
 2099                     out << 
"substr_wrapper(symTable.resolve(";
 
 2100                     visit(args[0], out);
 
 2102                     visit(args[1], out);
 
 2104                     visit(args[2], out);
 
 2112                     fatal(
"ICE: functor `%s` must map onto `NestedIntrinsicOperator`", op.getOperator());
 
 2116 #undef MINMAX_SYMBOL 
 2119         void visitNestedIntrinsicOperator(
const NestedIntrinsicOperator& op, std::ostream& out)
 override {
 
 2122             auto emitHelper = [&](
auto&& func) {
 
 2123                 tfm::format(out, 
"%s(%s, [&](auto&& env%d) {\n", func,
 
 2124                         join(op.getArguments(), 
",", [&](
auto& os, 
auto* arg) { return visit(arg, os); }),
 
 2126                 visitTupleOperation(op, out);
 
 2132             auto emitRange = [&](
char const* ty) {
 
 2133                 return emitHelper(
tfm::format(
"souffle::evaluator::runRange<%s>", ty));
 
 2136             switch (op.getFunction()) {
 
 2137                 case NestedIntrinsicOp::RANGE: 
return emitRange(
"RamSigned");
 
 2138                 case NestedIntrinsicOp::URANGE: 
return emitRange(
"RamUnsigned");
 
 2139                 case NestedIntrinsicOp::FRANGE: 
return emitRange(
"RamFloat");
 
 2145         void visitUserDefinedOperator(
const UserDefinedOperator& op, std::ostream& out)
 override {
 
 2146             const std::string& name = op.getName();
 
 2148             auto args = op.getArguments();
 
 2149             if (op.isStateful()) {
 
 2150                 out << name << 
"(&symTable, &recordTable";
 
 2151                 for (
auto& arg : args) {
 
 2157                 const std::vector<TypeAttribute>& argTypes = op.getArgsTypes();
 
 2160                     out << 
"symTable.lookup(";
 
 2164                 for (
size_t i = 0; 
i < args.size(); 
i++) {
 
 2168                     switch (argTypes[
i]) {
 
 2170                             out << 
"((RamSigned)";
 
 2171                             visit(args[
i], out);
 
 2175                             out << 
"((RamUnsigned)";
 
 2176                             visit(args[
i], out);
 
 2180                             out << 
"((RamFloat)";
 
 2181                             visit(args[
i], out);
 
 2185                             out << 
"symTable.resolve(";
 
 2186                             visit(args[
i], out);
 
 2202         void visitPackRecord(
const PackRecord& 
pack, std::ostream& out)
 override {
 
 2205             out << 
"pack(recordTable," 
 2206                 << 
"Tuple<RamDomain," << 
pack.getArguments().size() << 
">";
 
 2207             if (
pack.getArguments().size() == 0) {
 
 2210                 out << 
"{{ramBitCast(" << 
join(
pack.getArguments(), 
"),ramBitCast(", rec) << 
")}}\n";
 
 2219         void visitSubroutineArgument(
const SubroutineArgument& arg, std::ostream& out)
 override {
 
 2220             out << 
"(args)[" << arg.getArgument() << 
"]";
 
 2225         void visitSubroutineReturn(
const SubroutineReturn& ret, std::ostream& out)
 override {
 
 2226             out << 
"std::lock_guard<std::mutex> guard(lock);\n";
 
 2227             for (
auto val : ret.getValues()) {
 
 2229                     out << 
"ret.push_back(0);\n";
 
 2231                     out << 
"ret.push_back(";
 
 2240         void visitUndefValue(
const UndefValue&, std::ostream& )
 override {
 
 2241             fatal(
"Compilation error");
 
 2244         void visitNode(
const Node& node, std::ostream& )
 override {
 
 2245             fatal(
"Unsupported node type: %s", 
typeid(node).name());
 
 2249     out << std::setprecision(std::numeric_limits<RamFloat>::max_digits10);
 
 2251     CodeEmitter(*this).visit(stmt, out);
 
 2258     const SymbolTable& symTable = translationUnit.getSymbolTable();
 
 2259     const Program& prog = translationUnit.getProgram();
 
 2265     withSharedLibrary = 
false;
 
 2267     std::string classname = 
"Sf_" + 
id;
 
 2272         os << 
"#define _SOUFFLE_STATS\n";
 
 2274     os << 
"\n#include \"souffle/CompiledSouffle.h\"\n";
 
 2276         os << 
"#include <mutex>\n";
 
 2277         os << 
"#include \"souffle/provenance/Explain.h\"\n";
 
 2281         os << 
"#include <thread>\n";
 
 2282         os << 
"#include \"souffle/profile/Tui.h\"\n";
 
 2286     std::map<std::string, std::tuple<TypeAttribute, std::vector<TypeAttribute>, 
bool>> functors;
 
 2288         if (functors.find(op.getName()) == functors.end()) {
 
 2289             functors[op.getName()] = std::make_tuple(op.getReturnType(), op.getArgsTypes(), op.isStateful());
 
 2291         withSharedLibrary = 
true;
 
 2293     os << 
"extern \"C\" {\n";
 
 2294     for (
const auto& f : functors) {
 
 2296         const std::string& name = f.first;
 
 2298         const auto& functorTypes = f.second;
 
 2299         const auto& returnType = std::get<0>(functorTypes);
 
 2300         const auto& argsTypes = std::get<1>(functorTypes);
 
 2301         const auto& stateful = std::get<2>(functorTypes);
 
 2317             os << 
"souffle::RamDomain " << name << 
"(souffle::SymbolTable *, souffle::RecordTable *";
 
 2318             for (
size_t i = 0; 
i < argsTypes.size(); 
i++) {
 
 2319                 os << 
",souffle::RamDomain";
 
 2323             tfm::format(os, 
"%s %s(%s);\n", cppTypeDecl(returnType), name,
 
 2324                     join(
map(argsTypes, cppTypeDecl), 
","));
 
 2329     os << 
"namespace souffle {\n";
 
 2330     os << 
"static const RamDomain RAM_BIT_SHIFT_MASK = RAM_DOMAIN_SIZE - 1;\n";
 
 2333     for (
auto rel : prog.getRelations()) {
 
 2335         auto relationType = Relation::getSynthesiserRelation(*
rel, idxAnalysis->getIndexes(
rel->getName()),
 
 2338         generateRelationTypeStruct(os, std::move(relationType));
 
 2342     os << 
"class " << classname << 
" : public SouffleProgram {\n";
 
 2346     os << 
"static inline bool regex_wrapper(const std::string& pattern, const std::string& text) {\n";
 
 2347     os << 
"   bool result = false; \n";
 
 2348     os << 
"   try { result = std::regex_match(text, std::regex(pattern)); } catch(...) { \n";
 
 2349     os << 
"     std::cerr << \"warning: wrong pattern provided for match(\\\"\" << pattern << \"\\\",\\\"\" " 
 2350           "<< text << \"\\\").\\n\";\n}\n";
 
 2351     os << 
"   return result;\n";
 
 2356     os << 
"static inline std::string substr_wrapper(const std::string& str, size_t idx, size_t len) {\n";
 
 2357     os << 
"   std::string result; \n";
 
 2358     os << 
"   try { result = str.substr(idx,len); } catch(...) { \n";
 
 2359     os << 
"     std::cerr << \"warning: wrong index position provided by substr(\\\"\";\n";
 
 2360     os << 
"     std::cerr << str << \"\\\",\" << (int32_t)idx << \",\" << (int32_t)len << \") " 
 2362     os << 
"   } return result;\n";
 
 2366         os << 
"std::string profiling_fname;\n";
 
 2372     os << 
"// -- initialize symbol table --\n";
 
 2374     os << 
"SymbolTable symTable";
 
 2375     if (symTable.size() > 0) {
 
 2377         for (
size_t i = 0; 
i < symTable.size(); 
i++) {
 
 2378             os << 
"\tR\"_(" << symTable.resolve(
i) << 
")_\",\n";
 
 2385     os << 
"// -- initialize record table --\n";
 
 2387     os << 
"RecordTable recordTable;" 
 2394         os << 
"  size_t freqs[" << numFreq << 
"]{};\n";
 
 2396         for (
auto rel : prog.getRelations()) {
 
 2397             if (!
rel->isTemp()) {
 
 2401         os << 
"  size_t reads[" << numRead << 
"]{};\n";
 
 2405     std::stringstream initCons;     
 
 2406     std::stringstream registerRel;  
 
 2407     auto initConsSep = [&, empty = 
true]() 
mutable -> std::stringstream& {
 
 2408         initCons << (empty ? 
"\n: " : 
"\n, ");
 
 2415         initConsSep() << 
"profiling_fname(std::move(pf))";
 
 2419     std::set<std::string> storeRelations;
 
 2420     std::set<std::string> loadRelations;
 
 2421     std::set<const IO*> loadIOs;
 
 2422     std::set<const IO*> storeIOs;
 
 2426         auto op = io.get(
"operation");
 
 2427         if (op == 
"input") {
 
 2428             loadRelations.insert(io.getRelation());
 
 2429             loadIOs.insert(&io);
 
 2430         } 
else if (op == 
"printsize" || op == 
"output") {
 
 2431             storeRelations.insert(io.getRelation());
 
 2432             storeIOs.insert(&io);
 
 2434             assert(
"wrong I/O operation");
 
 2438     for (
auto rel : prog.getRelations()) {
 
 2440         const std::string& datalogName = 
rel->getName();
 
 2441         const std::string& cppName = getRelationName(*
rel);
 
 2444         auto relationType = Relation::getSynthesiserRelation(*
rel, idxAnalysis->getIndexes(datalogName),
 
 2446         const std::string& 
type = relationType->getTypeName();
 
 2449         os << 
"// -- Table: " << datalogName << 
"\n";
 
 2451         os << 
"Own<" << 
type << 
"> " << cppName << 
" = mk<" << 
type << 
">();\n";
 
 2452         if (!
rel->isTemp()) {
 
 2453             tfm::format(os, 
"souffle::RelationWrapper<%s> wrapper_%s;\n", 
type, cppName);
 
 2455             auto strLitAry = [](
auto&& xs) {
 
 2456                 std::stringstream 
ss;
 
 2457                 ss << 
"std::array<const char *," << xs.size() << 
">{{" 
 2458                    << 
join(xs, 
",", [](
auto&& os, 
auto&& x) { os << 
'"' << x << 
'"'; }) << 
"}}";
 
 2462             auto foundIn = [&](
auto&& set) { 
return contains(set, 
rel->getName()) ? 
"true" : 
"false"; };
 
 2464             tfm::format(initConsSep(), 
"wrapper_%s(%s, *%s, *this, \"%s\", %s, %s, %s)", cppName, relCtr++,
 
 2465                     cppName, datalogName, strLitAry(
rel->getAttributeTypes()),
 
 2466                     strLitAry(
rel->getAttributeNames()), 
rel->getAuxiliaryArity());
 
 2467             tfm::format(registerRel, 
"addRelation(\"%s\", wrapper_%s, %s, %s);\n", datalogName, cppName,
 
 2468                     foundIn(loadRelations), foundIn(storeRelations));
 
 2476     os << (
Global::config().has(
"profile") ? 
"(std::string pf=\"profile.log\")" : 
"()");
 
 2477     os << initCons.str() << 
'\n';
 
 2480         os << 
"ProfileEventSingleton::instance().setOutputFile(profiling_fname);\n";
 
 2482     os << registerRel.str();
 
 2486     os << 
"~" << classname << 
"() {\n";
 
 2496 std::string             inputDirectory; 
 2497 std::string             outputDirectory; 
 2498 SignalHandler*          signalHandler {SignalHandler::instance()}; 
 2499 std::atomic<RamDomain>  ctr {}; 
 2500 std::atomic<size_t>     iter {}; 
 2501 bool                    performIO = false; 
 2503 void runFunction(std::string  inputDirectoryArg   = "", 
 2504                  std::string  outputDirectoryArg  = "", 
 2505                  bool         performIOArg        = false) { 
 2506     this->inputDirectory  = std::move(inputDirectoryArg); 
 2507     this->outputDirectory = std::move(outputDirectoryArg); 
 2508     this->performIO       = performIOArg; 
 2510     // set default threads (in embedded mode) 
 2511     // if this is not set, and omp is used, the default omp setting of number of cores is used. 
 2512 #if defined(_OPENMP) 
 2513     if (0 < getNumThreads()) { omp_set_num_threads(getNumThreads()); } 
 2516     signalHandler->set(); 
 2519         os << 
"signalHandler->enableLogging();\n";
 
 2523     os << 
"// -- query evaluation --\n";
 
 2525         os << 
"ProfileEventSingleton::instance().startTimer();\n";
 
 2526         os << R
"_(ProfileEventSingleton::instance().makeTimeEvent("@time;starttime");)_" << '\n';
 
 2528            << R
"_(Logger logger("@runtime;", 0);)_" << '\n';
 
 2530         size_t relationCount = 0;
 
 2531         for (
auto rel : prog.getRelations()) {
 
 2532             if (
rel->getName()[0] != 
'@') {
 
 2537         os << R
"_(ProfileEventSingleton::instance().makeConfigRecord("relationCount", std::to_string()_" 
 2538            << relationCount << "));";
 
 2542     emitCode(os, prog.getMain());
 
 2546         os << 
"ProfileEventSingleton::instance().stopTimer();\n";
 
 2547         os << 
"dumpFreqs();\n";
 
 2551     os << 
"\n// -- relation hint statistics --\n";
 
 2554         for (
auto rel : prog.getRelations()) {
 
 2555             auto name = getRelationName(*
rel);
 
 2556             os << 
"std::cout << \"Statistics for Relation " << name << 
":\\n\";\n";
 
 2557             os << name << 
"->printStatistics(std::cout);\n";
 
 2558             os << 
"std::cout << \"\\n\";\n";
 
 2562     os << 
"signalHandler->reset();\n";
 
 2567     os << 
"public:\nvoid run() override { runFunction(\"\", \"\", " 
 2569     os << 
"public:\nvoid runAll(std::string inputDirectoryArg = \"\", std::string outputDirectoryArg = \"\") " 
 2572         os << 
"std::thread profiler([]() { profile::Tui().runProf(); });\n";
 
 2574     os << 
"runFunction(inputDirectoryArg, outputDirectoryArg, true);\n";
 
 2576         os << 
"if (profiler.joinable()) { profiler.join(); }\n";
 
 2581     os << 
"void printAll(std::string outputDirectoryArg = \"\") override {\n";
 
 2584     auto printDirectives = [&](
const std::map<std::string, std::string>& registry) {
 
 2585         auto cur = registry.begin();
 
 2586         if (cur == registry.end()) {
 
 2589         os << 
"{{\"" << cur->first << 
"\",\"" << 
escape(cur->second) << 
"\"}";
 
 2591         for (; cur != registry.end(); ++cur) {
 
 2592             os << 
",{\"" << cur->first << 
"\",\"" << 
escape(cur->second) << 
"\"}";
 
 2597     for (
auto store : storeIOs) {
 
 2598         auto const& directive = store->getDirectives();
 
 2600         os << 
"std::map<std::string, std::string> directiveMap(";
 
 2601         printDirectives(directive);
 
 2603         os << R
"_(if (!outputDirectoryArg.empty()) {)_"; 
 2604         os << R"_(directiveMap["output-dir"] = outputDirectoryArg;)_"; 
 2606         os << 
"IOSystem::getInstance().getWriter(";
 
 2607         os << 
"directiveMap, symTable, recordTable";
 
 2608         os << 
")->writeAll(*" << getRelationName(lookup(store->getRelation())) << 
");\n";
 
 2610         os << 
"} catch (std::exception& e) {std::cerr << e.what();exit(1);}\n";
 
 2616     os << 
"void loadAll(std::string inputDirectoryArg = \"\") override {\n";
 
 2618     for (
auto load : loadIOs) {
 
 2620         os << 
"std::map<std::string, std::string> directiveMap(";
 
 2621         printDirectives(load->getDirectives());
 
 2623         os << R
"_(if (!inputDirectoryArg.empty()) {)_"; 
 2624         os << R"_(directiveMap["fact-dir"] = inputDirectoryArg;)_"; 
 2626         os << 
"IOSystem::getInstance().getReader(";
 
 2627         os << 
"directiveMap, symTable, recordTable";
 
 2628         os << 
")->readAll(*" << getRelationName(lookup(load->getRelation()));
 
 2630         os << 
"} catch (std::exception& e) {std::cerr << \"Error loading data: \" << e.what() << " 
 2636     auto dumpRelation = [&](
const ram::Relation& ramRelation) {
 
 2637         const auto& relName = getRelationName(ramRelation);
 
 2638         const auto& name = ramRelation.getName();
 
 2639         const auto& attributesTypes = ramRelation.getAttributeTypes();
 
 2641         Json relJson = 
Json::object{{
"arity", 
static_cast<long long>(attributesTypes.size())},
 
 2642                 {
"auxArity", 
static_cast<long long>(0)},
 
 2643                 {
"types", 
Json::array(attributesTypes.begin(), attributesTypes.end())}};
 
 2648         os << 
"std::map<std::string, std::string> rwOperation;\n";
 
 2649         os << 
"rwOperation[\"IO\"] = \"stdout\";\n";
 
 2650         os << R
"(rwOperation["name"] = ")" << name << "\";\n";
 
 2651         os << 
"rwOperation[\"types\"] = ";
 
 2654         os << 
"IOSystem::getInstance().getWriter(";
 
 2655         os << 
"rwOperation, symTable, recordTable";
 
 2656         os << 
")->writeAll(*" << relName << 
");\n";
 
 2657         os << 
"} catch (std::exception& e) {std::cerr << e.what();exit(1);}\n";
 
 2662     os << 
"void dumpInputs() override {\n";
 
 2663     for (
auto load : loadIOs) {
 
 2664         dumpRelation(*lookup(load->getRelation()));
 
 2670     os << 
"void dumpOutputs() override {\n";
 
 2671     for (
auto store : storeIOs) {
 
 2672         dumpRelation(*lookup(store->getRelation()));
 
 2677     os << 
"SymbolTable& getSymbolTable() override {\n";
 
 2678     os << 
"return symTable;\n";
 
 2681     os << 
"RecordTable& getRecordTable() override {\n";
 
 2682     os << 
"return recordTable;\n";
 
 2685     if (!prog.getSubroutines().empty()) {
 
 2687         os << 
"void executeSubroutine(std::string name, const std::vector<RamDomain>& args, " 
 2688               "std::vector<RamDomain>& ret) override {\n";
 
 2690         size_t subroutineNum = 0;
 
 2691         for (
auto& 
sub : prog.getSubroutines()) {
 
 2692             os << 
"if (name == \"" << 
sub.first << 
"\") {\n" 
 2693                << 
"subroutine_" << subroutineNum
 
 2699         os << 
"fatal(\"unknown subroutine\");\n";
 
 2704         for (
auto& 
sub : prog.getSubroutines()) {
 
 2706             os << 
"#ifdef _MSC_VER\n";
 
 2707             os << 
"#pragma warning(disable: 4100)\n";
 
 2708             os << 
"#endif // _MSC_VER\n";
 
 2712                << 
"subroutine_" << subroutineNum
 
 2713                << 
"(const std::vector<RamDomain>& args, " 
 2714                   "std::vector<RamDomain>& ret) {\n";
 
 2717             bool needLock = 
false;
 
 2720                 os << 
"std::mutex lock;\n";
 
 2724             emitCode(os, *
sub.second);
 
 2730             os << 
"#ifdef _MSC_VER\n";
 
 2731             os << 
"#pragma warning(default: 4100)\n";
 
 2732             os << 
"#endif // _MSC_VER\n";
 
 2741         os << 
"void dumpFreqs() {\n";
 
 2742         for (
auto const& cur : idxMap) {
 
 2743             os << 
"\tProfileEventSingleton::instance().makeQuantityEvent(R\"_(" << cur.first << 
")_\", freqs[" 
 2744                << cur.second << 
"],0);\n";
 
 2746         for (
auto const& cur : neIdxMap) {
 
 2747             os << 
"\tProfileEventSingleton::instance().makeQuantityEvent(R\"_(@relation-reads;" << cur.first
 
 2748                << 
")_\", reads[" << cur.second << 
"],0);\n";
 
 2755     os << 
"SouffleProgram *newInstance_" << 
id << 
"(){return new " << classname << 
";}\n";
 
 2756     os << 
"SymbolTable *getST_" << 
id << 
"(SouffleProgram *p){return &reinterpret_cast<" << classname
 
 2757        << 
"*>(p)->symTable;}\n";
 
 2759     os << 
"\n#ifdef __EMBEDDED_SOUFFLE__\n";
 
 2760     os << 
"class factory_" << classname << 
": public souffle::ProgramFactory {\n";
 
 2761     os << 
"SouffleProgram *newInstance() {\n";
 
 2762     os << 
"return new " << classname << 
"();\n";
 
 2765     os << 
"factory_" << classname << 
"() : ProgramFactory(\"" << 
id << 
"\"){}\n";
 
 2767     os << 
"extern \"C\" {\n";
 
 2768     os << 
"factory_" << classname << 
" __factory_" << classname << 
"_instance;\n";
 
 2773     os << 
"int main(int argc, char** argv)\n{\n";
 
 2777     os << 
"souffle::CmdOptions opt(";
 
 2791     os << 
"if (!opt.parse(argc,argv)) return 1;\n";
 
 2795         os << classname + 
" obj(opt.getProfileName());\n";
 
 2797         os << classname + 
" obj;\n";
 
 2800     os << 
"#if defined(_OPENMP) \n";
 
 2801     os << 
"obj.setNumThreads(opt.getNumJobs());\n";
 
 2805         os << R
"_(souffle::ProfileEventSingleton::instance().makeConfigRecord("", opt.getSourceFileName());)_" 
 2807         os << R
"_(souffle::ProfileEventSingleton::instance().makeConfigRecord("fact-dir", opt.getInputFileDir());)_" 
 2809         os << R
"_(souffle::ProfileEventSingleton::instance().makeConfigRecord("jobs", std::to_string(opt.getNumJobs()));)_" 
 2811         os << R
"_(souffle::ProfileEventSingleton::instance().makeConfigRecord("output-dir", opt.getOutputFileDir());)_" 
 2813         os << R
"_(souffle::ProfileEventSingleton::instance().makeConfigRecord("version", ")_" 
 2816     os << 
"obj.runAll(opt.getInputFileDir(), opt.getOutputFileDir());\n";
 
 2819         os << 
"explain(obj, false);\n";
 
 2821         os << 
"explain(obj, true);\n";
 
 2823     os << 
"return 0;\n";
 
 2824     os << 
"} catch(std::exception &e) { souffle::SignalHandler::instance()->error(e.what());}\n";