Generate code. 
numeric coersions follow C++ semantics.
  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);